diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 925ac7e8fe..e6fa6d7203 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -17,58 +17,57 @@ jobs: strategy: matrix: cfg: - - { name: 'Linux', os: 'ubuntu-22.04' } - - { name: 'MacOS', os: 'macos-13' } + - { name: 'Linux', os: 'ubuntu-24.04' } + - { name: 'MacOS', os: 'macos-15' } steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: install GNU tools - if: matrix.cfg.os == 'macos-13' + if: matrix.cfg.os == 'macos-15' run: | brew install gnu-sed - echo "/usr/local/opt/gnu-sed/libexec/gnubin" >> ${GITHUB_PATH} + echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> ${GITHUB_PATH} - name: check-source.sh run: ../tools/check-source.sh - name: update brew - if: matrix.cfg.os == 'macos-13' - run: | - brew update + if: matrix.cfg.os == 'macos-15' + run: brew update - name: update-apt-cache - if: matrix.cfg.os == 'ubuntu-22.04' + if: matrix.cfg.os == 'ubuntu-24.04' run: sudo apt-get update - name: install (Linux) - if: matrix.cfg.os == 'ubuntu-22.04' + if: matrix.cfg.os == 'ubuntu-24.04' run: sudo apt-get install latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended lmodern - name: install (MacOS) - if: matrix.cfg.os == 'macos-13' + if: matrix.cfg.os == 'macos-15' run: | brew install basictex eval "$(/usr/libexec/path_helper)" echo "PATH=${PATH}" >> ${GITHUB_ENV} sudo tlmgr update --self - sudo tlmgr install latexmk isodate substr relsize ulem fixme rsfs extract layouts enumitem l3packages l3kernel imakeidx splitindex xstring + sudo tlmgr install latexmk isodate substr relsize ulem fixme rsfs environ layouts enumitem l3packages l3kernel imakeidx splitindex xstring - name: make (Linux) - if: matrix.cfg.os == 'ubuntu-22.04' + if: matrix.cfg.os == 'ubuntu-24.04' run: make quiet - name: make (MacOS) - if: matrix.cfg.os == 'macos-13' + if: matrix.cfg.os == 'macos-15' run: make full - name: check-output.sh run: ../tools/check-output.sh - name: upload PDF - if: matrix.cfg.os == 'ubuntu-22.04' - uses: actions/upload-artifact@v3 + if: matrix.cfg.os == 'ubuntu-24.04' + uses: actions/upload-artifact@v4 with: name: draft-snapshot path: source/std.pdf diff --git a/.gitorder b/.gitorder index abebabaa77..edc39fbf98 100644 --- a/.gitorder +++ b/.gitorder @@ -5,6 +5,7 @@ source/macros.tex source/tables.tex source/cover-*.tex source/front.tex +source/preface.tex source/intro.tex source/lex.tex source/basic.tex @@ -21,22 +22,24 @@ source/lib-intro.tex source/support.tex source/concepts.tex source/diagnostics.tex +source/memory.tex +source/meta.tex source/utilities.tex -source/strings.tex source/containers.tex source/iterators.tex source/ranges.tex source/algorithms.tex +source/strings.tex +source/text.tex source/numerics.tex source/time.tex -source/locales.tex source/iostreams.tex -source/regex.tex -source/atomics.tex source/threads.tex +source/exec.tex source/grammar.tex source/limits.tex source/compatibility.tex source/future.tex +source/uax31.tex source/back.tex source/xrefdelta.tex diff --git a/papers/n4972.html b/papers/n4972.html new file mode 100644 index 0000000000..61df993043 --- /dev/null +++ b/papers/n4972.html @@ -0,0 +1,846 @@ + + + + + +N4972 + + +

N4972 Editors’ Report:
Programming Languages — C++

+ +

Date: 2023-12-18

+ +

Thomas Köppe (editor, Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor, Bright Side Computing, LLC)
+Richard Smith (co-editor, Google Inc)

+ +

Email: cxxeditor@gmail.com

+ +

Acknowledgements

+ +

Thanks to all those who have submitted editorial +issues +and to those who have provided pull requests with fixes, +and special thanks to Johel Ernesto Guerrero Peña for providing in-depth review +of many of the draft motion applications.

+ +

New papers

+ + + +

Motions incorporated into working draft

+ +

Notes on motions

+ +

All motions were applied cleanly, and the following additional changes applied +for the sake of integration:

+ + + +

The feature test macro __cpp_lib_span has been modified both LWG Poll 3 and +LWG Poll 10, and is now set to a common, updated value (202311L).

+ +

The linear algebra paper P1673R13 moved by LWG Poll 19 adds a substantial amount +of material, and numerous minor issues were discovered during application, many +of which have been fixed immediately, and some will be addressed in future +editorial work. One particular issue, which is not new and also affects the +random number and special maths functions, is how to relate variables in code +and mathematical variables in a mathematical expression.

+ +

Core working group polls

+ +

CWG Poll 1: Accept as a Defect Report and apply the proposed resolution of all issues in +P3046R0 +(Core Language Working Group "ready" Issues for the November, 2023 meeting) to the C++ Working Paper.

+ +

CWG Poll 2: Accept as a Defect Report and apply the changes in +P2308R1 +(Template parameter initialization) to the C++ Working Paper.

+ +

CWG Poll 3: Apply the changes in +P2662R3 +(Pack Indexing) to the C++ Working Paper.

+ +

CWG Poll 4: Apply the changes in +P2864R2 +(Remove Deprecated Arithmetic Conversion on Enumerations From C++26) to the C++ Working Paper.

+ +

CWG Poll 5 was withdrawn.

+ +

Library working group polls

+ +

LWG Poll 1: Apply the changes for all Ready and Tentatively Ready issues in +P3040R0 +(C++ Standard Library Issues to be moved in Kona, Nov. 2023) to the C++ working paper.

+ +

LWG Poll 2: Apply the changes in +P0543R3 +(Saturation arithmetic) to the C++ working paper.

+ +

LWG Poll 3: Apply the changes in +P2407R5 +(Freestanding Library: Partial Classes) to the C++ working paper.

+ +

LWG Poll 4: Apply the changes in +P2546R5 +(Debugging Support) to the C++ working paper.

+ +

LWG Poll 5: Accept as a Defect Report and apply the changes in +P2905R2 +(Runtime format strings) to the C++ working paper.

+ +

LWG Poll 6: Apply the changes in +P2918R2 +(Runtime format strings II) to the C++ working paper.

+ +

LWG Poll 7: Accept as a Defect Report and apply the changes in +P2909R4 +(Fix formatting of code units as integers (Dude, where's my char?)) to the C++ working paper.

+ +

LWG Poll 8: Apply the changes in +P0952R2 +(A new specification for std::generate_canonical) to the C++ working paper.

+ +

LWG Poll 9: Apply the changes in +P2447R6 +(std::span over an initializer list) to the C++ working paper.

+ +

LWG Poll 10: Apply the changes in +P2821R5 +(span.at()) to the C++ working paper.

+ +

LWG Poll 11: Apply the changes in +P2868R3 +(Remove Deprecated std::allocator Typedef From C++26) to the C++ working paper.

+ +

LWG Poll 12: Apply the changes in +P2870R3 +(Remove basic_string::reserve() From C++26) to the C++ working paper.

+ +

LWG Poll 13: Apply the changes in +P2871R3 +(Remove Deprecated Unicode Conversion Facets from C++26) to the C++ working paper.

+ +

LWG Poll 14: Apply the changes in +P2819R2 +(Add tuple protocol to complex) to the C++ working paper.

+ +

LWG Poll 15: Apply the changes in +P2937R0 +(Freestanding: Remove strtok) to the C++ working paper.

+ +

LWG Poll 16: Apply the changes in +P2833R2 +(Freestanding Library: inout expected span) to the C++ working paper.

+ +

LWG Poll 17: Accept as a Defect Report and apply the changes in +P2836R1 +(std::basic_const_iterator should follow its underlying type's convertibility) to the C++ working paper.

+ +

LWG Poll 18: Apply the changes in +P2264R7 +(Make assert() macro user friendly for C and C++) to the C++ working paper.

+ +

LWG Poll 19: Apply the changes in +P1673R13 +(A free function linear algebra interface based on the BLAS) to the C++ working paper.

+ +

Comments on the Draft International Standard

+ +

This report includes our final dispositions on the Draft International Standard (DIS) +ballot comments for C++23 from national bodies and the ISO secretariat. Some of them only apply +to the published standard document and not the working draft, and the corresponding edits do not +appear in the working draft commit history. All comments on the ballot were editorial.

+ + + +

Editorial changes

+ +

Major editorial changes

+ +

A number of editorial changes were made in response to requests from the ISO +secretariat during the publication of C++23. We list just a few noteworthy ones.

+ + + +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N4964 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 a27ede64fef7fda551d480e5a1cf1b9a73832574
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Tue Oct 24 20:55:27 2023 +0800
+
+    [span.cons] Add `std::` for `data(arr)` (#6632)
+
+commit 84c526ebbda74553bf935f35f5594b8d5591bce5
+Author: Casey Carter <Casey@Carter.net>
+Date:   Mon Oct 30 14:22:57 2023 -0700
+
+    [format.formatter.spec] Add missing include to example (#6636)
+
+    The example code refers to `std::string` directly so it should `#include<string>`.
+
+commit 4a6f2e3f4791c44b8c8f32a75d0bebac4a7b6a9e
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Nov 2 00:53:04 2023 +0100
+
+    [intro.refs] Move nicknames for standards to relevant subclauses
+
+commit dc6eed02986d9c3c6827c710adb577ba0809f939
+Author: Krystian Stasiowski <sdkrystian@gmail.com>
+Date:   Tue Nov 7 04:32:19 2023 -0500
+
+    [dcl.dcl, over.best.ics, temp.param, class.union.anon] Remove mentions of "storage class" (#3906)
+
+commit 17c09925b2423c596196d3f88a61ff7b4052ef7a
+Author: Krystian Stasiowski <sdkrystian@gmail.com>
+Date:   Tue Nov 7 01:16:28 2023 -0500
+
+    [class.conv.fct] Fix reference to 'ref-qualifier-seq'
+
+commit 90720a35b0c3d65488d9dc9ecea682c271f43d52
+Author: A. Jiang <de34@live.cn>
+Date:   Mon Oct 30 09:34:01 2023 +0800
+
+    [queue.syn] Show `formatter` specializations in the synopsis
+
+commit e43aa89a4882f8080fb10c843cdb25c9740b65c7
+Author: A. Jiang <de34@live.cn>
+Date:   Mon Oct 30 09:36:24 2023 +0800
+
+    [stack.syn] Show the `formatter` specialization in the synopsis
+
+commit 80a8748fd401cfceee804bc96d2bfc518726d2e7
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Thu Oct 12 18:24:21 2023 -0400
+
+    [class.copy.assign] Remove a superfluous note.
+
+    Alternatively we could have added the word "non-object"; or changed
+    it to say "An overloaded assignment operator must be a member function";
+    but it doesn't seem like it needs to be here at all.
+
+commit c9c69dc54052badeb9b80458027371438d886763
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Thu Oct 12 18:58:39 2023 -0400
+
+    [class.copy.assign] Add some missing "non-object"s
+
+commit 2b5fc2936f12f73e975dbb9f34d3790fe0aa708f
+Author: Matt Bentley <mattreecebentley@gmail.com>
+Date:   Wed Nov 8 14:56:22 2023 +1300
+
+    [sequence.reqmts] Remove misleading, oversimplified informative text
+
+commit 11334c71244a046f0c29b01dfd79b35f6fea8cc4
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Sep 1 09:29:01 2023 +0200
+
+    [class.copy.elision] improve reference and replace informal term
+
+commit 4feefb62e0419bb52c678389163729959785d44a
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Wed Nov 8 02:59:01 2023 +0100
+
+    [mem.res.pool.options] Change "field" to "member" (#6479)
+
+commit a700e3b87b00d2673b3cded0a61201d09dfc051a
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Wed Nov 8 10:01:46 2023 +0800
+
+     [version.syn] Bump value of __cpp_lib_constexpr_complex (#6421)
+
+    P1383R2 "More constexpr for <cmath> and <complex>" modifies two headers;
+    both __cpp_lib_constexpr_cmath and __cpp_lib_constexpr_complex should be updated.
+
+    This aligns with existing practice in SD6.
+
+commit e9fb04e1c1e67bfb07bf3c61145b9d63a0f0adcf
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Tue Sep 27 15:36:08 2022 -0400
+
+    [dcl.enum] Enumerators don't have "initializers"
+
+commit bc3cb41a36dfff0d2358f4e294be9636590e680e
+Author: Krystian Stasiowski <sdkrystian@gmail.com>
+Date:   Tue Nov 7 21:08:15 2023 -0500
+
+    [dcl.name] Turn informative wording into note (#3964)
+
+commit 82b2ba6f6245e717cb002a9a836117a918aab36a
+Author: Patrick Johnston <gcupcakekid@gmail.com>
+Date:   Wed Nov 8 02:10:58 2023 +0000
+
+    [streambuf.general] Remove incorrect "abstract"
+
+    The referenced class template `basic_streambuf` is not abstract.
+
+commit bbaa4a497e03d944fc38279db4d8c47eed7831d9
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Oct 12 20:51:57 2023 +0200
+
+    [basic.lval] turn reference paragraph into note
+
+commit a03b8b70d6666b67d27c801b68d41683e987e929
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Thu Oct 5 15:27:29 2023 -0400
+
+    [temp.param] Introduce term to xref structural type
+
+    The current cross-references to [temp.param] appear confusing,
+    as the structural type definition is buried a couple of pages
+    below.  Also, this change looks clearer in the source.
+
+commit 71ee18ab8cd9efca0d8afa1f6e639cb02610a52b
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Nov 7 16:18:40 2023 -1000
+
+    [basic.types.general] Introduce term to xref implicit-lifetime type (#6591)
+
+commit 21454c7ebf67a1a723b61c32901a842c684e6b94
+Author: Language Lawyer <language.lawyer@gmail.com>
+Date:   Wed Aug 23 01:35:22 2023 +0500
+
+    [intro.races] Make reading atomic objects nondeterministic
+
+commit df26017a6bfd74d794345ea9313eae1efacbf7c9
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Wed Nov 8 03:31:10 2023 +0100
+
+    [diff.dcl] Replace 'field initializers' with 'member initializers' (#6482)
+
+commit cc69fc0dd6b1a2fdc834bade578acb84cc7d2cfa
+Author: A. Jiang <de34@live.cn>
+Date:   Wed Nov 8 10:54:52 2023 +0800
+
+    [intro.races] Remove inappropriate uses of "shall" (#6457)
+
+commit 60e280391a06b8d27f778a56310b0827109623aa
+Author: Eisenwave <me@eisenwave.net>
+Date:   Thu Aug 31 00:19:24 2023 +0200
+
+    [cmath.syn] fix misaligned parameter lists
+
+commit 646bfb2a060e3c7f490f6c4672ee93a0cbaf6d0d
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Nov 8 05:59:28 2023 -1000
+
+    [container.alloc.reqmts] Better xrefs for allocator-aware containers
+
+    There are now more allocator-aware containers in the standard
+    than when this subclause was first written, so ensure we have
+    call outs to all relevent subclauses.
+
+    The current wording for 'basic_stacktrace' also shows how
+    containers can properly call out the allocator-aware container
+    requirements, now that they have their own, titled subclause.
+
+commit 62e33ca8a0a55764227e6a67c1f554783ffefe40
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Thu Nov 9 00:01:38 2023 +0800
+
+    [time.zone.leap.overview] Fix example (#6383)
+
+commit 07ae51af31587ac533b1b39c95777ecb725dcab0
+Author: A. Jiang <de34@live.cn>
+Date:   Wed Jan 25 18:22:53 2023 +0800
+
+    [expr.prim.req.general] Correct the IFNDR example
+
+commit f3059744c84f561f8ead4c5d117bc1160c43b7e2
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed Nov 8 23:52:44 2023 +0000
+
+    [defns.character.container] Improve note to entry (#6644)
+
+commit 8b38857b22f6518a41e506e4c9b2e9a1792a0fbd
+Author: A. Jiang <de34@live.cn>
+Date:   Tue Oct 10 09:40:20 2023 +0800
+
+    [iterator.requirements.general] Clarify non-forward iterator
+
+commit fbb1a6ebbd1f78e644df2dbcb3ce31250410779e
+Author: onihusube <44743040+onihusube@users.noreply.github.com>
+Date:   Fri Nov 10 08:36:12 2023 +0900
+
+    [execpol.unseq] Fix missing \itemdescr (#5931)
+
+commit 10e2799f5d524dd941d424dfd08927c77a6b87f1
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Fri Feb 17 10:47:28 2023 -0500
+
+    [pairs.pair] Consistent wording for assignment
+
+    Apply a consistent pattern to how we specify assigning members in assignment operators.
+
+commit 78300aa38c23f1356dca8e786205e5aaf7769d01
+Author: Barry Revzin <barry.revzin@gmail.com>
+Date:   Thu Nov 9 14:45:17 2023 -1000
+
+    [class.compare] Don't introduce `V` for the return value (#6035)
+
+    In both cases, I'm not sure introducing `V` helps much - just requires name lookup for `V`. If we just say "the return value" in every case, I think that's clearer.
+
+commit 838cb0649b1f4061e960772aee3563cedb20b108
+Author: Michael Florian Hava <mfh@live.at>
+Date:   Thu Nov 9 13:51:58 2023 -1000
+
+    [basic.extended.fp] Replaced usage of 'mantissa' with 'significand'
+    according to SO/IEC/IEEE 60559:2008
+
+commit ce5ef1b5334f1fc756d40e40ec300257b0ff99d9
+Author: Michael Florian Hava <mfh@live.at>
+Date:   Thu Nov 9 13:57:32 2023 -1000
+
+    [numeric.limits.members] Replaced usage of 'mantissa' with 'significand' according to
+    SO/IEC/IEEE 60559:2008
+
+commit 3e1f377a9dc3bece7acd2dddb7237065504db65c
+Author: Brian Bi <bbi5291@gmail.com>
+Date:   Thu Nov 9 16:00:22 2023 -1000
+
+    [macros, styles] Add \hypertarget to headings (#6516)
+
+    This allows forming URLs with a stable label as a fragment and
+    have PDF viewers jump to the corresponding (sub)clause.
+
+    For example: std.pdf#basic.life
+
+commit 60f7bb72cdd36e9d359fa7aea84a5b836079a0ed
+Author: Eisenwave <me@eisenwave.net>
+Date:   Thu Jul 6 13:41:56 2023 +0200
+
+    [namespace.std] convert (a) and (b) notation to items
+
+commit f48f316c42c6cb67058d9f9106852154497b4516
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Fri Nov 10 06:57:17 2023 +0100
+
+    [atomics.order] Use "recommended practice" (#6380)
+
+commit 1ec1d9e6fa98734b3edf20f6c2217a4482f78103
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Nov 10 16:59:21 2023 +0800
+
+    [meta.{unary.prop.query,trans.arr] Use `static_assert` instead of `assert` in example
+
+commit bd8f4540720e52dab9187a62c5598e735aeacfdd
+Author: Eisenwave <me@eisenwave.net>
+Date:   Sat Aug 19 15:57:39 2023 +0200
+
+    [expr.sizeof] use constexpr member in example
+
+commit b1f922a126dcda78acb4bae055843e7a7321fe1d
+Author: Eisenwave <me@eisenwave.net>
+Date:   Wed Aug 23 13:42:39 2023 +0200
+
+    [basic.def.odr] Fix hyphenation of "{copy,move} assignment"
+
+commit 54e465a17adfcba56a57ff2fefe43ec898725efb
+Author: Eisenwave <me@eisenwave.net>
+Date:   Wed Aug 23 13:43:46 2023 +0200
+
+    [res.on.arguments] Fix hyphenation of "move assignment"
+
+commit 3c5b5b0c58d0440233d992e1a0791a449936f203
+Author: Eisenwave <me@eisenwave.net>
+Date:   Wed Aug 23 13:44:40 2023 +0200
+
+    [futures.{unique,shared}.future] Fix hyphenation of "{copy,move} assignment"
+
+commit 9483cb7cf6973689ad563d30778d8da2dff42a8d
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed Nov 8 22:57:57 2023 +0000
+
+    [string.capacity] Remove parentheses from "reserve()"
+
+    It's very confusing to talk about `reserve()` when describing a call to
+    `reserve(size_type)`, given that the overload `reserve()` also exists.
+
+commit 2a9f28670a0df6e239d9b335bdb014f20f577732
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Mon Jul 24 16:19:01 2023 +0000
+
+    [dcl.meaning.general] Use 'declarator-id' instead of 'name'
+
+commit d8b72f0ceb36b3537ef576ab216d588642e332ab
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Tue Jul 25 18:26:03 2023 +0000
+
+    [module.global.frag] Simplify wording
+
+    Also make variable order consistent across bullets.
+
+commit f0c172c5604b47c3ecc7b64669aad660df403624
+Author: Oliver Rosten <oliver.rosten@gmail.com>
+Date:   Fri Nov 10 18:12:06 2023 +0000
+
+    [algorithms] Change stable label "mismatch" to "alg.mismatch" (#6653)
+
+commit d97603a90d2fcfeec2caf4371ca9e6c8f562842a
+Author: A. Jiang <de34@live.cn>
+Date:   Sat Nov 11 03:21:17 2023 +0800
+
+    [forward.iterators] Use "Cpp17" requirement (#6612)
+
+commit f474227b69d10350999a5fc63503725421a89954
+Author: Geng Cheng <xmcgcg@qq.com>
+Date:   Sat Nov 11 10:25:39 2023 +0800
+
+    [stringstream.general] Add missing template argument "Allocator" (#6560)
+
+commit f5fdfe453e5a1e0370f2cb28bfc2dfeecab6370e
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Nov 8 15:12:16 2023 -1000
+
+    [diff.cpp20.library] Add missing new headers for C++23
+
+commit 38dfe3db0f08bd09a2b445ba82e83f7caae28d94
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Nov 9 11:00:44 2023 +0800
+
+    [dcl.init.ref] Clarify "related type"
+
+    "Related type" is not a term, "reference-related type" is clearer.
+
+commit 979983929bb592c02c9ae3e52f1c676dd5ae06fe
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Nov 14 02:27:01 2023 +0800
+
+    [range.cartesian.view] Don't name unused template parameter (#6177)
+
+commit ecbeb5ad4e4c0ac1d0cdb5e8dd01daab8df8d62e
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Nov 14 14:27:27 2023 -0500
+
+    [diff.cpp23.library] Entry for new headers in C++26 (#6648)
+
+commit eb7f0bcbff2af109643089ef36dfe67040a27f4a
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Nov 13 01:12:50 2023 -1000
+
+    [intro.defs, macros] Add cross-references among definitions
+
+    Fixes ISO/CS 017 (C++23 DIS).
+
+commit 706880e4ed855ae76d503c70adfb0015bbfb3df0
+Author: Lewis Baker <lewissbaker@users.noreply.github.com>
+Date:   Thu Nov 16 10:36:25 2023 +1030
+
+    [allocator.requirements.general] Fix missing ellipsis (#6695)
+
+commit 5c0103c0a656cbcd725780388b0879e992a1b21a
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Thu Nov 16 15:38:47 2023 +0000
+
+    [stacktrace.format], [stacktrace.basic.hash] change rSec3 to rSec2
+
+    These should not be nested below std::basic_stacktrace because they
+    apply to both std::stacktrace_entry and std::basic_stacktrace.
+
+commit a6ad6083ab75901cb41b5bc8d034c0b322433457
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Dec 5 23:42:23 2023 +0000
+
+    [std, styles] Adjust table captions as per ISO request
+
+    ISO has asked for captions to be bold and table numbers to be
+    separated by a dash.
+
+commit f519ea4aa97592703ba5bbe9164242d946723721
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Dec 7 01:00:53 2023 +0100
+
+    [intro.refs, time.format] Update references from ISO 8601:2004 to ISO 8601-1:2019 (#6720)
+
+commit 37956fb3685c2c279bd6b4b701964b20913d0c79
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Dec 6 19:01:29 2023 +0000
+
+    [syntax] Change "italic" to "italic, sans-serif"
+
+    We changed the grammar non-terminal font to sans-serif,
+    so we should update the description.
+
+commit 4eed7a0f1e44c45554f8a210af34fd6e1ea19596
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Dec 7 22:13:35 2023 +0100
+
+    [intro.abstract] Actually use the phrase 'unspecified/undefined behavior'
+
+    Fixes ISO/CS 011 (C++23 DIS).
+
+commit f8a6138da1e431779ac43a893faa32f3f0cad7d0
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Dec 7 12:45:11 2023 +0000
+
+    [intro.defs] Fix introductory text according to ISO rules.
+
+    In principle, "symbols and abbreviated terms" can be listed in a
+    standard, and can be listed in a separate clause or in a combined
+    clause 3 "Terms, definitions, symbols and abbreviated terms", we do
+    not actually need symbol definitions. In any case, the introductory
+    text would never mention "symbols".
+
+commit 9961cd4f16aca645c77d6927526ea71f635a2932
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Dec 7 00:01:48 2023 +0000
+
+    [introduction] A minimal "Introduction" clause
+
+    This clause explains our conventions regarding stable labels and
+    choice of fonts.
+
+commit 9041b27206388fecd03073bb913185ac738c6dca
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Dec 18 00:57:45 2023 +0000
+
+    [optional.monaic] Restore wording effected by LWG3973.
+
+    Both LWG3973 (Motion 1) and P2407R5 (Motion 3) modified this wording:
+    LWG3973 changes "value()" to "*val" to address ADL concerns, and
+    P2407R5 changed "value()" to "**this" to be freestanding. In light of
+    the former, the latter should also use "*val".
+
+    Independently, additional problems have been discovered with LWG3973,
+    but those will be addressed by a future LWG issue.
+
+commit 2b1867a3404562c4261722e0a913cbcbf5a0a476
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Dec 17 23:10:44 2023 +0000
+
+    [version.syn] New feature test macro __cpp_lib_freestanding_numeric
+
+    This macro indicates that freestanding support for "saturation
+    arithmetic" is available, which was added in motion LWG-2 (via
+    P0543R3). This reverts the previous change
+    148e03a16d53ff8cffd219384df37efad5fd386d, which I had made subsequent
+    to motion LWG-3 (P2407R5), on advice of LWG. A separate macro is
+    preferable to mixing both headers under "algorithm".
+
+commit fa54f9e7306b3d0abb21a82b5cc951711c96161f
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed Dec 13 11:03:18 2023 +0000
+
+    [range.access.general] Use consistent "In addition to being available ..." form
+
+    Elsewhere we say "the header" or "any of the headers", e.g. [meta.trans.other],
+    [tuple.helper], etc.
+
+commit 8c611593555b93a45a13543ad265d8cfaf646932
+Author: Cassio Neri <cassio.neri@gmail.com>
+Date:   Mon Nov 27 19:47:29 2023 +0000
+
+    [expected.general] Fix description of expected<T, E> (issue #6714.)
+
+commit 12565ed5ea083761b25df3c8325989f95fa04898
+Author: Po-yao Chang <poyaoc97@gmail.com>
+Date:   Wed Nov 22 23:02:49 2023 +0800
+
+    [class.eq] Fix the return value of a defaulted == operator function
+
+ + diff --git a/papers/n4972.md b/papers/n4972.md new file mode 100644 index 0000000000..ed66878372 --- /dev/null +++ b/papers/n4972.md @@ -0,0 +1,699 @@ +# N4972 Editors' Report -- Programming Languages -- C++ + +Date: 2023-12-18 + +Thomas Köppe (editor, Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor, Bright Side Computing, LLC) +Richard Smith (co-editor, Google Inc) + +Email: `cxxeditor@gmail.com` + +## Acknowledgements + +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, +and special thanks to Johel Ernesto Guerrero Peña for providing in-depth review +of many of the draft motion applications. + +## New papers + + * [N4971](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4971.pdf) is the + current working draft for C++26. It replaces + [N4964](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4964.pdf). + * N4972 is this Editors' Report. + +## Motions incorporated into working draft + +### Notes on motions + +All motions were applied cleanly, and the following additional changes applied +for the sake of integration: + +* LWG Polls 1 and 3 both modified [optional.monadic]: + [LWG-3973](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3040r0.html#3973) + changed `**this` to `*val`, and + [P2407R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2407r5.html) + changed `value()` to `**this`. This has been reconciled by changing the + latter to `*val`, too. +* LWG Poll 2 created a freestanding facility (saturation arithmetic) but did + not define a freestanding feature test macro. We added the macro + `__cpp_lib_freestanding_numeric`, also defined in the `` header. + +The feature test macro `__cpp_lib_span` has been modified both LWG Poll 3 and +LWG Poll 10, and is now set to a common, updated value (`202311L`). + +The linear algebra paper P1673R13 moved by LWG Poll 19 adds a substantial amount +of material, and numerous minor issues were discovered during application, many +of which have been fixed immediately, and some will be addressed in future +editorial work. One particular issue, which is not new and also affects the +random number and special maths functions, is how to relate variables in code +and mathematical variables in a mathematical expression. + +### Core working group polls + +CWG Poll 1: Accept as a Defect Report and apply the proposed resolution of all issues in +[P3046R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3046r0.html) +(Core Language Working Group "ready" Issues for the November, 2023 meeting) to the C++ Working Paper. + +CWG Poll 2: Accept as a Defect Report and apply the changes in +[P2308R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2308r1.html) +(Template parameter initialization) to the C++ Working Paper. + +CWG Poll 3: Apply the changes in +[P2662R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2662r3.pdf) +(Pack Indexing) to the C++ Working Paper. + +CWG Poll 4: Apply the changes in +[P2864R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2864r2.pdf) +(Remove Deprecated Arithmetic Conversion on Enumerations From C++26) to the C++ Working Paper. + +CWG Poll 5 was withdrawn. + +### Library working group polls + +LWG Poll 1: Apply the changes for all Ready and Tentatively Ready issues in +[P3040R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3040r0.html) +(C++ Standard Library Issues to be moved in Kona, Nov. 2023) to the C++ working paper. + +LWG Poll 2: Apply the changes in +[P0543R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0543r3.html) +(Saturation arithmetic) to the C++ working paper. + +LWG Poll 3: Apply the changes in +[P2407R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2407r5.html) +(Freestanding Library: Partial Classes) to the C++ working paper. + +LWG Poll 4: Apply the changes in +[P2546R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2546r5.html) +(Debugging Support) to the C++ working paper. + +LWG Poll 5: Accept as a Defect Report and apply the changes in +[P2905R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2905r2.html) +(Runtime format strings) to the C++ working paper. + +LWG Poll 6: Apply the changes in +[P2918R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2918r2.html) +(Runtime format strings II) to the C++ working paper. + +LWG Poll 7: Accept as a Defect Report and apply the changes in +[P2909R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2909r4.html) +(Fix formatting of code units as integers (Dude, where's my char?)) to the C++ working paper. + +LWG Poll 8: Apply the changes in +[P0952R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0952r2.html) +(A new specification for `std::generate_canonical`) to the C++ working paper. + +LWG Poll 9: Apply the changes in +[P2447R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2447r6.html) +(`std::span` over an initializer list) to the C++ working paper. + +LWG Poll 10: Apply the changes in +[P2821R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2821r5.html) +(`span.at()`) to the C++ working paper. + +LWG Poll 11: Apply the changes in +[P2868R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2868r3.pdf) +(Remove Deprecated `std::allocator` Typedef From C++26) to the C++ working paper. + +LWG Poll 12: Apply the changes in +[P2870R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2870r3.pdf) +(Remove `basic_string::reserve()` From C++26) to the C++ working paper. + +LWG Poll 13: Apply the changes in +[P2871R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2871r3.pdf) +(Remove Deprecated Unicode Conversion Facets from C++26) to the C++ working paper. + +LWG Poll 14: Apply the changes in +[P2819R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2819r2.pdf) +(Add tuple protocol to `complex`) to the C++ working paper. + +LWG Poll 15: Apply the changes in +[P2937R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2937r0.html) +(Freestanding: Remove `strtok`) to the C++ working paper. + +LWG Poll 16: Apply the changes in +[P2833R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2833r2.html) +(Freestanding Library: `inout` `expected` `span`) to the C++ working paper. + +LWG Poll 17: Accept as a Defect Report and apply the changes in +[P2836R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2836r1.html) +(`std::basic_const_iterator` should follow its underlying type's convertibility) to the C++ working paper. + +LWG Poll 18: Apply the changes in +[P2264R7](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2264r7.html) +(Make `assert()` macro user friendly for C and C++) to the C++ working paper. + +LWG Poll 19: Apply the changes in +[P1673R13](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1673r13.html) +(A free function linear algebra interface based on the BLAS) to the C++ working paper. + +## Comments on the Draft International Standard + +This report includes our final dispositions on the Draft International Standard (DIS) +ballot comments for C++23 from national bodies and the ISO secretariat. Some of them only apply +to the published standard document and not the working draft, and the corresponding edits do not +appear in the working draft commit history. All comments on the ballot were editorial. + +* **ISO/CS 01:** Accepted. We added references to the tables. +* **ISO/CS 02:** Accepted. We moved the explanations close to their point of use. +* **ISO/CS 03:** Accepted. We are now referring to a specific element, and keeping the dated reference. +* **ISO/CS 04:** Accepted. +* **ISO/CS 05:** Rejected: We do not understand the justification "Since there is no specific element referenced this reference shall be undated." The Drafting Directives seem to make a clear case for when undated (10.4) and dated (10.5) references are appropriate, and we firmly fall into the case where an undated reference is inappropriate ("if it will be possible to use all future changes of the referenced document" is definitely not the case). Reference to a specific element does not seem to be required in order to permit the use of a dated reference. Even the House Style seems to permit dated references when necessary: "When referring to the whole document, use an undated document number unless it is necessary that the user refers to a specific edition". +* **ISO/CS 06:** Rejected: Moot by comment 05. +* **ISO/CS 07:** Rejected: Moot by comment 05. +* **ISO/CS 08:** Accepted. We reworded the reference to the Unicode standard to make the normative nature more obvious. +* **ISO/CS 09:** Accepted. +* **ISO/CS 10:** Rejected: We find domains valuable here, since the terms often sound like plain English words, but have rather domain-specific meaning, and the domain establishes important context to aid understandability. +* **ISO/CS 11:** Accepted with modifications: four unused definitions are removed. The remaining term, "unspecified behavior" is retained, since it captures a variety of patterns which are not lexically spelled "behavior" but are neatly covered by this umbrella term. +* **ISO/CS 12:** Accepted with modifications: we have italicized the cross-references. However, for the formal grammar terms that we display in italic sans font, please see the discussion on comment 32. +* **ISO/CS 13:** Rejected: The token "CE" is not an acronym, but a meta variable (like "x" or "y". It is typeset distinctly. The name is evocative of its use. +* **ISO/CS 14:** Accepted. +* **ISO/CS 15:** Accepted. +* **ISO/CS 16:** Rejected: The wording is correct as written. However, this is also mooted by comment 11, which deletes the wording in question. +* **ISO/CS 17:** Accepted. +* **ISO/CS 18:** Accepted. +* **ISO/CS 19:** Accepted. +* **CA 20:** n/a, comment was filed erroneously +* **JP 21:** Accepted. We added an example. +* **JP 22:** Rejected: No consensus for change; any attributes of a lambda-declarator are considered to be attached to the synthesized function call operator or operator template (i.e. the member function of the closure type), not the closure type itself. +* **JP 23:** Accepted with modifications: The example is written as intended. The comments in the example have been amended to clarify the exposition. +* **JP 24:** Accepted. +* **JP 25:** Accepted. +* **JP 26:** Rejected: No consensus for change; the example deliberately introduces a facility to aid comprehension. +* **JP 27:** Rejected: No consensus for change; the example deliberately introduces a facility to aid comprehension. +* **JP 28:** Rejected: No consensus for change; the example deliberately introduces a facility to aid comprehension. +* **ISO/CS 29:** Accepted. +* **ISO/CS 30:** Accepted. We added a note that refers to the annex. +* **ISO/CS 31:** Accepted. We had previously used foreword wording from an older document. +* **ISO/CS 32:** Rejected, along with comment 12: our document has complex typographic requirements, and we have carefully selected a harmonizing family of typefaces in our document processing system that meets our needs. For example, certain parts of a formal grammar (some of which appear in Clause 3; see comment 12) require typographic distinction to avoid ambiguity. We have discussed this with the ISO secretariat. +* **ISO/CS 33:** Rejected: We have an approved SC22 ballot to permit the use of paragraph numbers. (We also have a proposal for the JDMT to add such a permission to the Drafting Directives.) +* **ISO/CS 34:** Accepted. Reworded to clarify. +* **ISO/CS 35:** Accepted. +* **ISO/CS 36:** Accepted the notes and tables captioning changes. Rejected the UK English spelling: The document defines many terms that must be spelled the same way by conforming implementations and by users of those implementations, and these terms use US English spelling. It would be confusing for the document text to use UK English spelling when describing these terms. (This is the same disposition as for a similar comment on the DIS ballot of 14882:2017.) +* **ISO/CS 37:** Rejected, please see comment 39. +* **ISO/CS 38:** Accepted with modifications: We will review the presentation of cross-references in Clause 3. However, the use of italics in Clause 3 is not a regular "emphasis/definition" in body font, but rather a grammar production, which we typeset distinctly. Please also see the discussion regarding comment 32. +* **ISO/CS 39:** Rejected: For this comment and for comment 37, we have carefully reviewed the permitted verbal constructions. We believe that the notes are the best place for this explanatory, optional information, and the wording as-is accurately describes the consequences of normative requirements for illustrative purposes. We would like to not move this explanatory material into the main text, since that text already contains a complex range of requirements on the C++ language, its implementations, and its users, and our community has been finding our established boundary for what is explanatory note material helpful. +* **ISO/CS 40:** Accepted. The logic that processed the notes was erroneous and failed to handle subclauses with more than 9 notes; this has been fixed. + +## Editorial changes + +### Major editorial changes + +A number of editorial changes were made in response to requests from the ISO +secretariat during the publication of C++23. We list just a few noteworthy ones. + +* There is now a new "Introduction" subclause, which explains our use of + stable labels and some typographic choices. In the future, we would like to + expand the introduction to explain more comprehensively how the Standard is + structured, phrased, and intended to be read. +* Table captions are now formatted in bold, and the table number is separated + from the caption by a dash. +* Inadmissible text has been removed from Clauses 2 (Normative references) and + 3 (Terms and definitions), as those clauses must only contain specific, + fixed wording. The removed text has been moved nearer to the places in the + main text where it is needed. +* Definitions in Clause 3 (Terms and definitions) now contain cross references + to one another as appropriate. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N4964 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/n4964...n4971). + + commit a27ede64fef7fda551d480e5a1cf1b9a73832574 + Author: S. B. Tam + Date: Tue Oct 24 20:55:27 2023 +0800 + + [span.cons] Add `std::` for `data(arr)` (#6632) + + commit 84c526ebbda74553bf935f35f5594b8d5591bce5 + Author: Casey Carter + Date: Mon Oct 30 14:22:57 2023 -0700 + + [format.formatter.spec] Add missing include to example (#6636) + + The example code refers to `std::string` directly so it should `#include`. + + commit 4a6f2e3f4791c44b8c8f32a75d0bebac4a7b6a9e + Author: Jens Maurer + Date: Thu Nov 2 00:53:04 2023 +0100 + + [intro.refs] Move nicknames for standards to relevant subclauses + + commit dc6eed02986d9c3c6827c710adb577ba0809f939 + Author: Krystian Stasiowski + Date: Tue Nov 7 04:32:19 2023 -0500 + + [dcl.dcl, over.best.ics, temp.param, class.union.anon] Remove mentions of "storage class" (#3906) + + commit 17c09925b2423c596196d3f88a61ff7b4052ef7a + Author: Krystian Stasiowski + Date: Tue Nov 7 01:16:28 2023 -0500 + + [class.conv.fct] Fix reference to 'ref-qualifier-seq' + + commit 90720a35b0c3d65488d9dc9ecea682c271f43d52 + Author: A. Jiang + Date: Mon Oct 30 09:34:01 2023 +0800 + + [queue.syn] Show `formatter` specializations in the synopsis + + commit e43aa89a4882f8080fb10c843cdb25c9740b65c7 + Author: A. Jiang + Date: Mon Oct 30 09:36:24 2023 +0800 + + [stack.syn] Show the `formatter` specialization in the synopsis + + commit 80a8748fd401cfceee804bc96d2bfc518726d2e7 + Author: Arthur O'Dwyer + Date: Thu Oct 12 18:24:21 2023 -0400 + + [class.copy.assign] Remove a superfluous note. + + Alternatively we could have added the word "non-object"; or changed + it to say "An overloaded assignment operator must be a member function"; + but it doesn't seem like it needs to be here at all. + + commit c9c69dc54052badeb9b80458027371438d886763 + Author: Arthur O'Dwyer + Date: Thu Oct 12 18:58:39 2023 -0400 + + [class.copy.assign] Add some missing "non-object"s + + commit 2b5fc2936f12f73e975dbb9f34d3790fe0aa708f + Author: Matt Bentley + Date: Wed Nov 8 14:56:22 2023 +1300 + + [sequence.reqmts] Remove misleading, oversimplified informative text + + commit 11334c71244a046f0c29b01dfd79b35f6fea8cc4 + Author: Eisenwave + Date: Fri Sep 1 09:29:01 2023 +0200 + + [class.copy.elision] improve reference and replace informal term + + commit 4feefb62e0419bb52c678389163729959785d44a + Author: Jan Schultke + Date: Wed Nov 8 02:59:01 2023 +0100 + + [mem.res.pool.options] Change "field" to "member" (#6479) + + commit a700e3b87b00d2673b3cded0a61201d09dfc051a + Author: S. B. Tam + Date: Wed Nov 8 10:01:46 2023 +0800 + + [version.syn] Bump value of __cpp_lib_constexpr_complex (#6421) + + P1383R2 "More constexpr for and " modifies two headers; + both __cpp_lib_constexpr_cmath and __cpp_lib_constexpr_complex should be updated. + + This aligns with existing practice in SD6. + + commit e9fb04e1c1e67bfb07bf3c61145b9d63a0f0adcf + Author: Arthur O'Dwyer + Date: Tue Sep 27 15:36:08 2022 -0400 + + [dcl.enum] Enumerators don't have "initializers" + + commit bc3cb41a36dfff0d2358f4e294be9636590e680e + Author: Krystian Stasiowski + Date: Tue Nov 7 21:08:15 2023 -0500 + + [dcl.name] Turn informative wording into note (#3964) + + commit 82b2ba6f6245e717cb002a9a836117a918aab36a + Author: Patrick Johnston + Date: Wed Nov 8 02:10:58 2023 +0000 + + [streambuf.general] Remove incorrect "abstract" + + The referenced class template `basic_streambuf` is not abstract. + + commit bbaa4a497e03d944fc38279db4d8c47eed7831d9 + Author: Jan Schultke + Date: Thu Oct 12 20:51:57 2023 +0200 + + [basic.lval] turn reference paragraph into note + + commit a03b8b70d6666b67d27c801b68d41683e987e929 + Author: Alisdair Meredith + Date: Thu Oct 5 15:27:29 2023 -0400 + + [temp.param] Introduce term to xref structural type + + The current cross-references to [temp.param] appear confusing, + as the structural type definition is buried a couple of pages + below. Also, this change looks clearer in the source. + + commit 71ee18ab8cd9efca0d8afa1f6e639cb02610a52b + Author: Alisdair Meredith + Date: Tue Nov 7 16:18:40 2023 -1000 + + [basic.types.general] Introduce term to xref implicit-lifetime type (#6591) + + commit 21454c7ebf67a1a723b61c32901a842c684e6b94 + Author: Language Lawyer + Date: Wed Aug 23 01:35:22 2023 +0500 + + [intro.races] Make reading atomic objects nondeterministic + + commit df26017a6bfd74d794345ea9313eae1efacbf7c9 + Author: Jan Schultke + Date: Wed Nov 8 03:31:10 2023 +0100 + + [diff.dcl] Replace 'field initializers' with 'member initializers' (#6482) + + commit cc69fc0dd6b1a2fdc834bade578acb84cc7d2cfa + Author: A. Jiang + Date: Wed Nov 8 10:54:52 2023 +0800 + + [intro.races] Remove inappropriate uses of "shall" (#6457) + + commit 60e280391a06b8d27f778a56310b0827109623aa + Author: Eisenwave + Date: Thu Aug 31 00:19:24 2023 +0200 + + [cmath.syn] fix misaligned parameter lists + + commit 646bfb2a060e3c7f490f6c4672ee93a0cbaf6d0d + Author: Alisdair Meredith + Date: Wed Nov 8 05:59:28 2023 -1000 + + [container.alloc.reqmts] Better xrefs for allocator-aware containers + + There are now more allocator-aware containers in the standard + than when this subclause was first written, so ensure we have + call outs to all relevent subclauses. + + The current wording for 'basic_stacktrace' also shows how + containers can properly call out the allocator-aware container + requirements, now that they have their own, titled subclause. + + commit 62e33ca8a0a55764227e6a67c1f554783ffefe40 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Thu Nov 9 00:01:38 2023 +0800 + + [time.zone.leap.overview] Fix example (#6383) + + commit 07ae51af31587ac533b1b39c95777ecb725dcab0 + Author: A. Jiang + Date: Wed Jan 25 18:22:53 2023 +0800 + + [expr.prim.req.general] Correct the IFNDR example + + commit f3059744c84f561f8ead4c5d117bc1160c43b7e2 + Author: Jonathan Wakely + Date: Wed Nov 8 23:52:44 2023 +0000 + + [defns.character.container] Improve note to entry (#6644) + + commit 8b38857b22f6518a41e506e4c9b2e9a1792a0fbd + Author: A. Jiang + Date: Tue Oct 10 09:40:20 2023 +0800 + + [iterator.requirements.general] Clarify non-forward iterator + + commit fbb1a6ebbd1f78e644df2dbcb3ce31250410779e + Author: onihusube <44743040+onihusube@users.noreply.github.com> + Date: Fri Nov 10 08:36:12 2023 +0900 + + [execpol.unseq] Fix missing \itemdescr (#5931) + + commit 10e2799f5d524dd941d424dfd08927c77a6b87f1 + Author: Alisdair Meredith + Date: Fri Feb 17 10:47:28 2023 -0500 + + [pairs.pair] Consistent wording for assignment + + Apply a consistent pattern to how we specify assigning members in assignment operators. + + commit 78300aa38c23f1356dca8e786205e5aaf7769d01 + Author: Barry Revzin + Date: Thu Nov 9 14:45:17 2023 -1000 + + [class.compare] Don't introduce `V` for the return value (#6035) + + In both cases, I'm not sure introducing `V` helps much - just requires name lookup for `V`. If we just say "the return value" in every case, I think that's clearer. + + commit 838cb0649b1f4061e960772aee3563cedb20b108 + Author: Michael Florian Hava + Date: Thu Nov 9 13:51:58 2023 -1000 + + [basic.extended.fp] Replaced usage of 'mantissa' with 'significand' + according to SO/IEC/IEEE 60559:2008 + + commit ce5ef1b5334f1fc756d40e40ec300257b0ff99d9 + Author: Michael Florian Hava + Date: Thu Nov 9 13:57:32 2023 -1000 + + [numeric.limits.members] Replaced usage of 'mantissa' with 'significand' according to + SO/IEC/IEEE 60559:2008 + + commit 3e1f377a9dc3bece7acd2dddb7237065504db65c + Author: Brian Bi + Date: Thu Nov 9 16:00:22 2023 -1000 + + [macros, styles] Add \hypertarget to headings (#6516) + + This allows forming URLs with a stable label as a fragment and + have PDF viewers jump to the corresponding (sub)clause. + + For example: std.pdf#basic.life + + commit 60f7bb72cdd36e9d359fa7aea84a5b836079a0ed + Author: Eisenwave + Date: Thu Jul 6 13:41:56 2023 +0200 + + [namespace.std] convert (a) and (b) notation to items + + commit f48f316c42c6cb67058d9f9106852154497b4516 + Author: Jan Schultke + Date: Fri Nov 10 06:57:17 2023 +0100 + + [atomics.order] Use "recommended practice" (#6380) + + commit 1ec1d9e6fa98734b3edf20f6c2217a4482f78103 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Nov 10 16:59:21 2023 +0800 + + [meta.{unary.prop.query,trans.arr] Use `static_assert` instead of `assert` in example + + commit bd8f4540720e52dab9187a62c5598e735aeacfdd + Author: Eisenwave + Date: Sat Aug 19 15:57:39 2023 +0200 + + [expr.sizeof] use constexpr member in example + + commit b1f922a126dcda78acb4bae055843e7a7321fe1d + Author: Eisenwave + Date: Wed Aug 23 13:42:39 2023 +0200 + + [basic.def.odr] Fix hyphenation of "{copy,move} assignment" + + commit 54e465a17adfcba56a57ff2fefe43ec898725efb + Author: Eisenwave + Date: Wed Aug 23 13:43:46 2023 +0200 + + [res.on.arguments] Fix hyphenation of "move assignment" + + commit 3c5b5b0c58d0440233d992e1a0791a449936f203 + Author: Eisenwave + Date: Wed Aug 23 13:44:40 2023 +0200 + + [futures.{unique,shared}.future] Fix hyphenation of "{copy,move} assignment" + + commit 9483cb7cf6973689ad563d30778d8da2dff42a8d + Author: Jonathan Wakely + Date: Wed Nov 8 22:57:57 2023 +0000 + + [string.capacity] Remove parentheses from "reserve()" + + It's very confusing to talk about `reserve()` when describing a call to + `reserve(size_type)`, given that the overload `reserve()` also exists. + + commit 2a9f28670a0df6e239d9b335bdb014f20f577732 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Mon Jul 24 16:19:01 2023 +0000 + + [dcl.meaning.general] Use 'declarator-id' instead of 'name' + + commit d8b72f0ceb36b3537ef576ab216d588642e332ab + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Tue Jul 25 18:26:03 2023 +0000 + + [module.global.frag] Simplify wording + + Also make variable order consistent across bullets. + + commit f0c172c5604b47c3ecc7b64669aad660df403624 + Author: Oliver Rosten + Date: Fri Nov 10 18:12:06 2023 +0000 + + [algorithms] Change stable label "mismatch" to "alg.mismatch" (#6653) + + commit d97603a90d2fcfeec2caf4371ca9e6c8f562842a + Author: A. Jiang + Date: Sat Nov 11 03:21:17 2023 +0800 + + [forward.iterators] Use "Cpp17" requirement (#6612) + + commit f474227b69d10350999a5fc63503725421a89954 + Author: Geng Cheng + Date: Sat Nov 11 10:25:39 2023 +0800 + + [stringstream.general] Add missing template argument "Allocator" (#6560) + + commit f5fdfe453e5a1e0370f2cb28bfc2dfeecab6370e + Author: Alisdair Meredith + Date: Wed Nov 8 15:12:16 2023 -1000 + + [diff.cpp20.library] Add missing new headers for C++23 + + commit 38dfe3db0f08bd09a2b445ba82e83f7caae28d94 + Author: A. Jiang + Date: Thu Nov 9 11:00:44 2023 +0800 + + [dcl.init.ref] Clarify "related type" + + "Related type" is not a term, "reference-related type" is clearer. + + commit 979983929bb592c02c9ae3e52f1c676dd5ae06fe + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Nov 14 02:27:01 2023 +0800 + + [range.cartesian.view] Don't name unused template parameter (#6177) + + commit ecbeb5ad4e4c0ac1d0cdb5e8dd01daab8df8d62e + Author: Alisdair Meredith + Date: Tue Nov 14 14:27:27 2023 -0500 + + [diff.cpp23.library] Entry for new headers in C++26 (#6648) + + commit eb7f0bcbff2af109643089ef36dfe67040a27f4a + Author: Thomas Köppe + Date: Mon Nov 13 01:12:50 2023 -1000 + + [intro.defs, macros] Add cross-references among definitions + + Fixes ISO/CS 017 (C++23 DIS). + + commit 706880e4ed855ae76d503c70adfb0015bbfb3df0 + Author: Lewis Baker + Date: Thu Nov 16 10:36:25 2023 +1030 + + [allocator.requirements.general] Fix missing ellipsis (#6695) + + commit 5c0103c0a656cbcd725780388b0879e992a1b21a + Author: Jonathan Wakely + Date: Thu Nov 16 15:38:47 2023 +0000 + + [stacktrace.format], [stacktrace.basic.hash] change rSec3 to rSec2 + + These should not be nested below std::basic_stacktrace because they + apply to both std::stacktrace_entry and std::basic_stacktrace. + + commit a6ad6083ab75901cb41b5bc8d034c0b322433457 + Author: Thomas Köppe + Date: Tue Dec 5 23:42:23 2023 +0000 + + [std, styles] Adjust table captions as per ISO request + + ISO has asked for captions to be bold and table numbers to be + separated by a dash. + + commit f519ea4aa97592703ba5bbe9164242d946723721 + Author: Jens Maurer + Date: Thu Dec 7 01:00:53 2023 +0100 + + [intro.refs, time.format] Update references from ISO 8601:2004 to ISO 8601-1:2019 (#6720) + + commit 37956fb3685c2c279bd6b4b701964b20913d0c79 + Author: Thomas Köppe + Date: Wed Dec 6 19:01:29 2023 +0000 + + [syntax] Change "italic" to "italic, sans-serif" + + We changed the grammar non-terminal font to sans-serif, + so we should update the description. + + commit 4eed7a0f1e44c45554f8a210af34fd6e1ea19596 + Author: Jens Maurer + Date: Thu Dec 7 22:13:35 2023 +0100 + + [intro.abstract] Actually use the phrase 'unspecified/undefined behavior' + + Fixes ISO/CS 011 (C++23 DIS). + + commit f8a6138da1e431779ac43a893faa32f3f0cad7d0 + Author: Thomas Köppe + Date: Thu Dec 7 12:45:11 2023 +0000 + + [intro.defs] Fix introductory text according to ISO rules. + + In principle, "symbols and abbreviated terms" can be listed in a + standard, and can be listed in a separate clause or in a combined + clause 3 "Terms, definitions, symbols and abbreviated terms", we do + not actually need symbol definitions. In any case, the introductory + text would never mention "symbols". + + commit 9961cd4f16aca645c77d6927526ea71f635a2932 + Author: Thomas Köppe + Date: Thu Dec 7 00:01:48 2023 +0000 + + [introduction] A minimal "Introduction" clause + + This clause explains our conventions regarding stable labels and + choice of fonts. + + commit 9041b27206388fecd03073bb913185ac738c6dca + Author: Thomas Köppe + Date: Mon Dec 18 00:57:45 2023 +0000 + + [optional.monaic] Restore wording effected by LWG3973. + + Both LWG3973 (Motion 1) and P2407R5 (Motion 3) modified this wording: + LWG3973 changes "value()" to "*val" to address ADL concerns, and + P2407R5 changed "value()" to "**this" to be freestanding. In light of + the former, the latter should also use "*val". + + Independently, additional problems have been discovered with LWG3973, + but those will be addressed by a future LWG issue. + + commit 2b1867a3404562c4261722e0a913cbcbf5a0a476 + Author: Thomas Köppe + Date: Sun Dec 17 23:10:44 2023 +0000 + + [version.syn] New feature test macro __cpp_lib_freestanding_numeric + + This macro indicates that freestanding support for "saturation + arithmetic" is available, which was added in motion LWG-2 (via + P0543R3). This reverts the previous change + 148e03a16d53ff8cffd219384df37efad5fd386d, which I had made subsequent + to motion LWG-3 (P2407R5), on advice of LWG. A separate macro is + preferable to mixing both headers under "algorithm". + + commit fa54f9e7306b3d0abb21a82b5cc951711c96161f + Author: Jonathan Wakely + Date: Wed Dec 13 11:03:18 2023 +0000 + + [range.access.general] Use consistent "In addition to being available ..." form + + Elsewhere we say "the header" or "any of the headers", e.g. [meta.trans.other], + [tuple.helper], etc. + + commit 8c611593555b93a45a13543ad265d8cfaf646932 + Author: Cassio Neri + Date: Mon Nov 27 19:47:29 2023 +0000 + + [expected.general] Fix description of expected (issue #6714.) + + commit 12565ed5ea083761b25df3c8325989f95fa04898 + Author: Po-yao Chang + Date: Wed Nov 22 23:02:49 2023 +0800 + + [class.eq] Fix the return value of a defaulted == operator function diff --git a/papers/n4982.html b/papers/n4982.html new file mode 100644 index 0000000000..3f97397fec --- /dev/null +++ b/papers/n4982.html @@ -0,0 +1,613 @@ + + + + + +N4982 + + +

N4982 Editors’ Report:
Programming Languages — C++

+ +

Date: 2024-04-16

+ +

Thomas Köppe (editor, Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor, Bright Side Computing, LLC)
+Richard Smith (co-editor, Google Inc)

+ +

Email: cxxeditor@gmail.com

+ +

Acknowledgements

+ +

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

+ +

New papers

+ +
    +
  • N4981 is the +current working draft for C++26. It replaces +N4971.
  • +
  • N4982 is this Editors' Report.
  • +
+ +

Motions incorporated into working draft

+ +

Notes on motions

+ +

All motions were applied cleanly.

+ +

Core working group polls

+ +

CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues in +P3196R0 +(Core Language Working Group "ready" Issues for the March, 2024 meeting) to the C++ Working Paper.

+ +

CWG Poll 2. Apply the changes in +P2748R5 +(Disallow Binding a Returned Glvalue to a Temporary) to the C++ Working Paper.

+ +

CWG Poll 3. Accept as a Defect Report and apply the changes in P3106R1 (Clarifying rules for brace elision in aggregate initialization) to the C++ Working Paper, resolving core issue 2149.

+ +

CWG Poll 4. Apply the changes in +P0609R3 +(Attributes for Structured Bindings) to the C++ Working Paper.

+ +

CWG Poll 5. Accept as a Defect Report and apply the changes in +P3034R1 +(Module Declarations Shouldn’t be Macros) to the C++ Working Paper.

+ +

CWG Poll 6. Accept as a Defect Report and apply the changes in +P2809R3 +(Trivial infinite loops are not Undefined Behavior) to the C++ Working Paper.

+ +

CWG Poll 7. Apply the changes in +P2795R5 +(Erroneous behaviour for uninitialized reads) to the C++ Working Paper.

+ +

CWG Poll 9. Apply the changes in +P2573R2 +(= delete("should have a reason");) to the C++ Working Paper.

+ +

CWG Poll 10. Apply the changes in +P2893R3 +(Variadic friends) to the C++ Working Paper.

+ +

CWG Poll 8 was withdrawn.

+ +

Library working group polls

+ +

LWG Poll 1: Apply the changes for all Ready and Tentatively Ready issues in +P3180R0 +(C++ Standard Library Ready Issues to be moved in Tokyo, Mar. 2024) to the C++ working paper.

+ +

LWG Poll 2: Apply the changes in +P2875R4 +(Undeprecate polymorphic_allocator::destroy for C++26) to the C++ working paper.

+ +

LWG Poll 3: Apply the changes in +P2867R2 +(Remove Deprecated strstreams From C++26) to the C++ working paper.

+ +

LWG Poll 4: Apply the changes in +P2869R4 +(Remove Deprecated shared_ptr Atomic Access APIs from C++26) to the C++ working paper.

+ +

LWG Poll 5: Apply the changes in +P2872R3 +(Remove wstring_convert From C++26) to the C++ working paper.

+ +

LWG Poll 6: Accept as a Defect Report and apply the changes in +P3107R5 +(Permit an efficient implementation of std::print) to the C++ working paper.

+ +

LWG Poll 7: Apply the changes in +P3142R0 +(Printing Blank Lines with println) to the C++ working paper.

+ +

LWG Poll 8: Apply the changes in +P2845R8 +(Formatting of std::filesystem::path) to the C++ working paper.

+ +

LWG Poll 9: Apply the changes in +P0493R5 +(Atomic minimum/maximum) to the C++ working paper.

+ +

LWG Poll 10: Apply the changes in +P2542R8 +(views::concat) to the C++ working paper.

+ +

LWG Poll 11: Apply the changes in +P2591R5 +(Concatenation of strings and string views) to the C++ working paper.

+ +

LWG Poll 12: Apply the changes in +P2248R8 +(Enabling list-initialization for algorithms) to the C++ working paper.

+ +

LWG Poll 13: Apply the changes in +P2810R4 +(is_debugger_present is_replaceable) to the C++ working paper.

+ +

LWG Poll 14: Apply the changes in +P1068R11 +(Vector API for random number generation) to the C++ working paper.

+ +

LWG Poll 16: Apply the changes in +P2944R3 +(Comparisons for reference_wrapper) to the C++ working paper.

+ +

LWG Poll 17: Apply the changes in +P2642R6 +(Padded mdspan layouts) to the C++ working paper.

+ +

LWG Poll 18: Apply the changes in +P3029R1 +(Better mdspan's CTAD) to the C++ working paper.

+ +

LWG Poll 15 was withdrawn.

+ +

Editorial changes

+ +

Major editorial changes

+ +

There have not been any major editorial changes since the last working draft.

+ +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N4971 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 08649a5a81ba91d8597c263b99dc80ed71767940
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Fri Dec 22 11:33:39 2023 +0100
+
+    [stmt.expr] Use \grammarterm for expression (#6469)
+
+commit acb68797051c9a6a5f51e4adb5091b376f1ba13a
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Mon Jan 1 16:23:56 2024 +0100
+
+    [basic.life] Fix indentation in example (#6727)
+
+commit f6692f25130834672ba5a212f739100669abbbe8
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Jan 2 20:21:54 2024 +0100
+
+    [basic.scope.pdecl,basic.types.general] Remove extra whitespace (#6756)
+
+commit 7ddcd43c96589fc13342ac4cee549da75360fde7
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Fri Jan 5 15:41:01 2024 -0500
+
+    [basic.scope.param] Add missing \grammarterm for requires-expression (#6759)
+
+commit 29c0e4882a1ae62e7cd5f8d3fabcb22ae6153219
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Dec 18 17:22:30 2023 +0100
+
+    [std] Remove problematic 'requires' phrases from notes.
+
+    Only specific phrases involving the word "required" are problematic,
+    namely when they appear to establish a normative requirement. They
+    have been reworded, often by replacing "is required" with "needs",
+    sometimes with slightly larger edits.
+
+commit 43fc5a16147e720568b68ecae77f12fa3fb15102
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Jan 5 15:32:55 2024 +0000
+
+    [std] Reword "necessary", "permitted", "allowed", "may" in notes.
+
+    This is so that notes do not (inappropriately) state requirements or
+    permissions.
+
+commit 74433025763f83bbccfb001dab8aa084647ffb2f
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Thu Jan 11 19:11:17 2024 +0100
+
+    [basic.def] Fix punctuation (#6766)
+
+commit b67e0b70e88abf65d9b49875133c68d55744b1de
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Jan 12 12:53:10 2024 +0000
+
+    [text.encoding.overview] Use same parameter names as detailed description (#6768)
+
+commit bc5a56b6e9cadd030d48066601fc8098382c7469
+Author: Casey Carter <Casey@Carter.net>
+Date:   Mon Jan 15 11:19:13 2024 -0800
+
+    [exception] Paragraph two is no longer universally true
+
+    We recently added `bad_expected_access<void>` to the Standard Library, which derives from `exception`, but does not have "the following publicly accessible member functions, each of them having a non-throwing exception specification." For clarity, we should point out that this provision is not universal.
+
+commit 2055c2feabee6ec9df24ea07f8451ad33618be45
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Jan 16 09:20:44 2024 +0100
+
+    [zombie.names] Remove superfluous period (#6774)
+
+commit 8410aac1b84ec161b6990441acde53185f958135
+Author: Daniel Krügler <daniel.kruegler@gmail.com>
+Date:   Sun Jan 21 22:39:02 2024 +0100
+
+    [tuple.helper] Paragraph 1 not universally true (#6777)
+
+    [tuple.helper] p1 defines a general requirement that all specializations of `tuple_size`
+    shall meet the *Cpp17UnaryTypeTrait* requirements, but p4 actually defines a
+    special situation where this requirement is not met ("Otherwise, it has no member value").
+    We have the same seemingly contradiction in [depr.tuple] p2. For clarity, we should
+    point out that this provision is not universal.
+
+commit 4fe9190fa05c4fb4e83c1a1ba68aa12aa49542e9
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Sat Jan 27 14:38:55 2024 +0800
+
+    [locale.ctype.members] Add missing parameter name
+
+commit 74f5f61cac56a4eca5389a51754fe7e60e6b7449
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Sat Jan 27 11:26:37 2024 +0000
+
+    [tuple.cnstr] Do not use code font for cardinal number 1 (#6785)
+
+commit cb8ff12806b67990665100baaacb9a16040bce8c
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sat Jan 27 17:11:23 2024 +0100
+
+    [container.alloc.reqmts] End note with period (#6787)
+
+commit 70b99af0dfcb9cae82bcd97c7b24a2e84edfb2cd
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sat Jan 27 18:03:16 2024 +0100
+
+    [class.mem.general,class.mfct.non.static] End note with period (#6778)
+
+commit db80a4612af561e8473fd8fb3724ae9db2c72578
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Feb 5 15:51:03 2024 +0000
+
+    [rand.dist.samp.plinear] Fix copy & paste error in Mandates (#6794)
+
+    This error was present in the incoming P1719R2 paper (Mandating the
+    Standard Library: Clause 26 - Numerics Library), but is obviously bogus.
+    There is no UnaryOperation type in that constructor. The correct
+    requirement is taken from the corresponding constructor in
+    [rand.dist.samp.pconst].
+
+commit e51d5733b1bd1531d6e3b63617d12414a56678c0
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Wed Feb 7 10:37:06 2024 -0500
+
+    [temp.res.general] Grammatical parallelism: remove a stray "a" (#6796)
+
+commit 8238252bcec14f76e97133db32721beaec5c749b
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Thu Feb 8 06:59:10 2024 +0100
+
+    [iterator.concept.winc] Fix typo (#6800)
+
+commit 19caa61068d3f3aa2453e1ba7256536b8464c25c
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Dec 28 10:07:15 2023 +0800
+
+    [mem.res.private] Say `*this` instead of improper  `this`
+
+commit 419190062806ae257e5efe7057551fd626bd9516
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Dec 28 10:08:04 2023 +0800
+
+    [mem.res.monotonic.buffer.mem] Say `*this` instead of improper `this`
+
+commit 6ecda0b20664fc6b8450157e1cd9f0580c32e5e1
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Dec 28 10:09:08 2023 +0800
+
+    [re.traits] Say `*this` instead of improper `this`
+
+commit 9305893dfd250d876edf4555cf96c665e2e71e75
+Author: Casey Carter <Casey@Carter.net>
+Date:   Thu Feb 15 13:16:33 2024 -0800
+
+    [thread.once.callonce] INVOKE is evaluated, not called (#6810)
+
+commit 3616a40ded794e94181a5405672b1c36f7774684
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Wed Feb 21 19:05:13 2024 +0100
+
+    [temp.pre] Add comma after introductory clause (#6814)
+
+commit 30debb0c5d5dc42fa36864aac76b82f49319ad84
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed Feb 21 21:39:56 2024 +0100
+
+    [temp.constr.order] Move index entry to correct paragraph (#6812)
+
+commit fb0277664fd53efea93d95202784f78aea610f31
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Feb 22 20:28:15 2024 +0100
+
+    [semaphore.syn] Add binary_semaphore to index (#6781)
+
+commit 090840673ee58d3c1e8d2844d3c716ee5ce245bc
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Feb 22 20:31:19 2024 +0100
+
+    [format.parse.ctx] Improve readability of paragraphs 12 and 14 (#6815)
+
+commit a5825b1905b06d730a46e64fb5b379f48cbc6e51
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Feb 22 20:33:18 2024 +0100
+
+    [format.parse.ctx] Add comma (#6817)
+
+commit 8c8e05d7ff6cda6329ca898e7a270547a85675d7
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Feb 22 20:35:21 2024 +0100
+
+    [format.parse.ctx] Move non-normative explanations of errors into notes (#6816)
+
+commit 48f90026631638c91b3d8138bed49cd0450380c7
+Author: Eisenwave <me@eisenwave.net>
+Date:   Wed Feb 28 10:23:51 2024 +0100
+
+    [stmt.while] Add comma after introductory phrase
+
+commit d5ad3794937429b1410071037af9ddfb0aa8c861
+Author: Eisenwave <me@eisenwave.net>
+Date:   Wed Feb 28 10:24:26 2024 +0100
+
+    [stmt.do] Add comma after introductory phrase
+
+commit 78ecd23f22f00be4bffaf806a6747417ce2150a2
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Wed Feb 28 18:06:26 2024 +0100
+
+    [stmt.jump] Add cross-reference to [stmt.dcl] for destruction of local variables (#6829)
+
+commit 66b6b97c8f3969f96e3ca8df1180c18b1c57af8c
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Wed Feb 28 21:50:50 2024 +0100
+
+    [expr.dynamic.cast] Add comma after conditional clause (#6830)
+
+commit 23430d7e605d62f5a4a1769611e3c415d6510b65
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Mar 1 11:06:34 2024 +0100
+
+    [bibliography] Replace HTTP link with HTTPS link (#6831)
+
+commit 20c2851a3c8f480a017cef6602b1b6a4d32bc5e4
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Mar 1 16:03:04 2024 +0100
+
+    [time.parse] Hyphenate argument-dependent lookup
+
+commit e0287d17110f86e3724bda5ebe74de249508490f
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Mar 1 16:04:02 2024 +0100
+
+    [diff.cpp17.temp] Hyphenate argument-dependent lookup
+
+commit ceff4ea83b511be01a8e1756386ce6a2e06e323c
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Fri Mar 1 18:06:00 2024 +0100
+
+    [headers] Strike incorrect quote of subclause heading (#6832)
+
+commit 9878cfbea12b517d32c5af1bbfa7c8b8c4ff9cab
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Sun Mar 3 08:42:45 2024 +0100
+
+    [handler.functions] Add cross-reference to [intro.races] (#6845)
+
+commit 9ec133c8e51aae98297255563250a2f6656e4636
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Tue Mar 19 15:36:51 2024 +0000
+
+    [time.hash] Fix spelling of 'Cpp17Hash'
+
+commit 2b7cd6e8be2bc8a9ae97da9bf03ae4efa7fe1a9c
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Apr 16 20:03:29 2024 +0800
+
+    [expos.only.entity] Add/fix \expos for exposition-only names (#6924)
+
+commit aa21c812f629975d5d25d4639053482f346751a8
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Tue Apr 16 08:07:44 2024 -0400
+
+    [dcl.type.elab] Move note to separate paragraph
+
+    Also clarify that the next paragraph is talking about any elaborated-type-specifier at all, not just the ones in p4.
+
+commit 397384c90e3ead9f832a3a269335fbfe53328180
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Feb 16 06:51:03 2024 +0100
+
+    [rand.adapt.ibits,rand.dist.pois.poisson] Add namespace std in class template
+
+    [rand.adapt.ibits] 28.5.5.3-4
+    [rand.dist.pois.poisson] 28.5.9.4.1-1
+
+commit fbf3d76683d269a0a5313fb69b5aa483ddd3a18a
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Feb 22 21:41:42 2024 +0100
+
+    [expr.unary.op] remove redundant value category wording
+
+commit 498cd7720bb2e53fb323144f956e67900a054e34
+Author: Daniel Krügler <daniel.kruegler@gmail.com>
+Date:   Sun Feb 4 17:57:38 2024 +0100
+
+    [iterator.requirements.general] Clarify that "constexpr iterator" is a requirement to be met
+
+    [iterator.requirements.general] p16 says "Iterators are called _constexpr iterators_ [..]", but all referencing sections say "meet the constexpr iterator requirements". For clarity, we should reword the definition to make it clear that this is a named requirement.
+
+commit 89cd1467f354a2b9b05ac57ad1f90f483aab22b9
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sun Jan 28 13:54:17 2024 +0800
+
+    [range.drop.overview] Remove redundant \iref for subrange
+
+    ..which already existed in the previous bullet.
+
+commit bee055de1c5e23ce0b301138998633dc64169b4a
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Nov 23 09:33:39 2023 +0800
+
+    [dcl.init.ref] Change "function lvalue" to "lvalue of function type"
+
+commit ce31d424ba6753be1c87a4cf3face42f89b9e010
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Nov 23 09:36:28 2023 +0800
+
+    [over.ics.ref] Simplify wording by not using "function lvalue"
+
+commit 2a07c133732dcc7ea57aeb32612b15b50837a4df
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Nov 23 09:38:41 2023 +0800
+
+    [over.ics.rank] Change "function lvalue" to "lvalue of function type"
+
+commit 7675c4c1abf1986241e8a20463fd71f2841d3c39
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Sep 1 10:27:25 2023 +0200
+
+    [res.on.exception.handling] use grammarterm instead of informal term and add ref
+
+ + diff --git a/papers/n4982.md b/papers/n4982.md new file mode 100644 index 0000000000..92a68b0900 --- /dev/null +++ b/papers/n4982.md @@ -0,0 +1,472 @@ +# N4982 Editors' Report -- Programming Languages -- C++ + +Date: 2024-04-16 + +Thomas Köppe (editor, Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor, Bright Side Computing, LLC) +Richard Smith (co-editor, Google Inc) + +Email: `cxxeditor@gmail.com` + +## Acknowledgements + +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 + + * [N4981](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4981.pdf) is the + current working draft for C++26. It replaces + [N4971](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4971.pdf). + * N4982 is this Editors' Report. + +## Motions incorporated into working draft + +### Notes on motions + +All motions were applied cleanly. + +### Core working group polls + +CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues in +[P3196R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3196r0.html) +(Core Language Working Group "ready" Issues for the March, 2024 meeting) to the C++ Working Paper. + +CWG Poll 2. Apply the changes in +[P2748R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2748r5.html) +(Disallow Binding a Returned Glvalue to a Temporary) to the C++ Working Paper. + +CWG Poll 3. Accept as a Defect Report and apply the changes in [P3106R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3106r1.html) (Clarifying rules for brace elision in aggregate initialization) to the C++ Working Paper, resolving core issue 2149. + +CWG Poll 4. Apply the changes in +[P0609R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0609r3.pdf) +(Attributes for Structured Bindings) to the C++ Working Paper. + +CWG Poll 5. Accept as a Defect Report and apply the changes in +[P3034R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3034r1.html) +(Module Declarations Shouldn’t be Macros) to the C++ Working Paper. + +CWG Poll 6. Accept as a Defect Report and apply the changes in +[P2809R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2809r3.html) +(Trivial infinite loops are not Undefined Behavior) to the C++ Working Paper. + +CWG Poll 7. Apply the changes in +[P2795R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2795r5.html) +(Erroneous behaviour for uninitialized reads) to the C++ Working Paper. + +CWG Poll 9. Apply the changes in +[P2573R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2573r2.html) +(`= delete("should have a reason");`) to the C++ Working Paper. + +CWG Poll 10. Apply the changes in +[P2893R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2893r3.html) +(Variadic friends) to the C++ Working Paper. + +CWG Poll 8 was withdrawn. + +### Library working group polls + +LWG Poll 1: Apply the changes for all Ready and Tentatively Ready issues in +[P3180R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3180r0.html) +(C++ Standard Library Ready Issues to be moved in Tokyo, Mar. 2024) to the C++ working paper. + +LWG Poll 2: Apply the changes in +[P2875R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2875r4.pdf) +(Undeprecate `polymorphic_allocator::destroy` for C++26) to the C++ working paper. + +LWG Poll 3: Apply the changes in +[P2867R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2867r2.html) +(Remove Deprecated `strstream`s From C++26) to the C++ working paper. + +LWG Poll 4: Apply the changes in +[P2869R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2869r4.pdf) +(Remove Deprecated `shared_ptr` Atomic Access APIs from C++26) to the C++ working paper. + +LWG Poll 5: Apply the changes in +[P2872R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2872r3.pdf) +(Remove `wstring_convert` From C++26) to the C++ working paper. + +LWG Poll 6: Accept as a Defect Report and apply the changes in +[P3107R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3107r5.html) +(Permit an efficient implementation of `std::print`) to the C++ working paper. + +LWG Poll 7: Apply the changes in +[P3142R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3142r0.pdf) +(Printing Blank Lines with `println`) to the C++ working paper. + +LWG Poll 8: Apply the changes in +[P2845R8](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2845r8.html) +(Formatting of `std::filesystem::path`) to the C++ working paper. + +LWG Poll 9: Apply the changes in +[P0493R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0493r5.pdf) +(Atomic minimum/maximum) to the C++ working paper. + +LWG Poll 10: Apply the changes in +[P2542R8](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2542r8.html) +(`views::concat`) to the C++ working paper. + +LWG Poll 11: Apply the changes in +[P2591R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2591r5.html) +(Concatenation of strings and string views) to the C++ working paper. + +LWG Poll 12: Apply the changes in +[P2248R8](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2248r8.html) +(Enabling list-initialization for algorithms) to the C++ working paper. + +LWG Poll 13: Apply the changes in +[P2810R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2810r4.html) +(`is_debugger_present` `is_replaceable`) to the C++ working paper. + +LWG Poll 14: Apply the changes in +[P1068R11](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1068r11.html) +(Vector API for random number generation) to the C++ working paper. + +LWG Poll 16: Apply the changes in +[P2944R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2944r3.html) +(Comparisons for `reference_wrapper`) to the C++ working paper. + +LWG Poll 17: Apply the changes in +[P2642R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2642r6.pdf) +(Padded `mdspan` layouts) to the C++ working paper. + +LWG Poll 18: Apply the changes in +[P3029R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3029r1.html) +(Better `mdspan`'s CTAD) to the C++ working paper. + +LWG Poll 15 was withdrawn. + +## Editorial changes + +### Major editorial changes + +There have not been any major editorial changes since the last working draft. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N4971 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/n4971...n4981). + + commit 08649a5a81ba91d8597c263b99dc80ed71767940 + Author: Jan Schultke + Date: Fri Dec 22 11:33:39 2023 +0100 + + [stmt.expr] Use \grammarterm for expression (#6469) + + commit acb68797051c9a6a5f51e4adb5091b376f1ba13a + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Mon Jan 1 16:23:56 2024 +0100 + + [basic.life] Fix indentation in example (#6727) + + commit f6692f25130834672ba5a212f739100669abbbe8 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Jan 2 20:21:54 2024 +0100 + + [basic.scope.pdecl,basic.types.general] Remove extra whitespace (#6756) + + commit 7ddcd43c96589fc13342ac4cee549da75360fde7 + Author: Alisdair Meredith + Date: Fri Jan 5 15:41:01 2024 -0500 + + [basic.scope.param] Add missing \grammarterm for requires-expression (#6759) + + commit 29c0e4882a1ae62e7cd5f8d3fabcb22ae6153219 + Author: Jens Maurer + Date: Mon Dec 18 17:22:30 2023 +0100 + + [std] Remove problematic 'requires' phrases from notes. + + Only specific phrases involving the word "required" are problematic, + namely when they appear to establish a normative requirement. They + have been reworded, often by replacing "is required" with "needs", + sometimes with slightly larger edits. + + commit 43fc5a16147e720568b68ecae77f12fa3fb15102 + Author: Thomas Köppe + Date: Fri Jan 5 15:32:55 2024 +0000 + + [std] Reword "necessary", "permitted", "allowed", "may" in notes. + + This is so that notes do not (inappropriately) state requirements or + permissions. + + commit 74433025763f83bbccfb001dab8aa084647ffb2f + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Thu Jan 11 19:11:17 2024 +0100 + + [basic.def] Fix punctuation (#6766) + + commit b67e0b70e88abf65d9b49875133c68d55744b1de + Author: Jonathan Wakely + Date: Fri Jan 12 12:53:10 2024 +0000 + + [text.encoding.overview] Use same parameter names as detailed description (#6768) + + commit bc5a56b6e9cadd030d48066601fc8098382c7469 + Author: Casey Carter + Date: Mon Jan 15 11:19:13 2024 -0800 + + [exception] Paragraph two is no longer universally true + + We recently added `bad_expected_access` to the Standard Library, which derives from `exception`, but does not have "the following publicly accessible member functions, each of them having a non-throwing exception specification." For clarity, we should point out that this provision is not universal. + + commit 2055c2feabee6ec9df24ea07f8451ad33618be45 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Jan 16 09:20:44 2024 +0100 + + [zombie.names] Remove superfluous period (#6774) + + commit 8410aac1b84ec161b6990441acde53185f958135 + Author: Daniel Krügler + Date: Sun Jan 21 22:39:02 2024 +0100 + + [tuple.helper] Paragraph 1 not universally true (#6777) + + [tuple.helper] p1 defines a general requirement that all specializations of `tuple_size` + shall meet the *Cpp17UnaryTypeTrait* requirements, but p4 actually defines a + special situation where this requirement is not met ("Otherwise, it has no member value"). + We have the same seemingly contradiction in [depr.tuple] p2. For clarity, we should + point out that this provision is not universal. + + commit 4fe9190fa05c4fb4e83c1a1ba68aa12aa49542e9 + Author: S. B. Tam + Date: Sat Jan 27 14:38:55 2024 +0800 + + [locale.ctype.members] Add missing parameter name + + commit 74f5f61cac56a4eca5389a51754fe7e60e6b7449 + Author: Jonathan Wakely + Date: Sat Jan 27 11:26:37 2024 +0000 + + [tuple.cnstr] Do not use code font for cardinal number 1 (#6785) + + commit cb8ff12806b67990665100baaacb9a16040bce8c + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sat Jan 27 17:11:23 2024 +0100 + + [container.alloc.reqmts] End note with period (#6787) + + commit 70b99af0dfcb9cae82bcd97c7b24a2e84edfb2cd + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sat Jan 27 18:03:16 2024 +0100 + + [class.mem.general,class.mfct.non.static] End note with period (#6778) + + commit db80a4612af561e8473fd8fb3724ae9db2c72578 + Author: Jonathan Wakely + Date: Mon Feb 5 15:51:03 2024 +0000 + + [rand.dist.samp.plinear] Fix copy & paste error in Mandates (#6794) + + This error was present in the incoming P1719R2 paper (Mandating the + Standard Library: Clause 26 - Numerics Library), but is obviously bogus. + There is no UnaryOperation type in that constructor. The correct + requirement is taken from the corresponding constructor in + [rand.dist.samp.pconst]. + + commit e51d5733b1bd1531d6e3b63617d12414a56678c0 + Author: Arthur O'Dwyer + Date: Wed Feb 7 10:37:06 2024 -0500 + + [temp.res.general] Grammatical parallelism: remove a stray "a" (#6796) + + commit 8238252bcec14f76e97133db32721beaec5c749b + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Thu Feb 8 06:59:10 2024 +0100 + + [iterator.concept.winc] Fix typo (#6800) + + commit 19caa61068d3f3aa2453e1ba7256536b8464c25c + Author: A. Jiang + Date: Thu Dec 28 10:07:15 2023 +0800 + + [mem.res.private] Say `*this` instead of improper `this` + + commit 419190062806ae257e5efe7057551fd626bd9516 + Author: A. Jiang + Date: Thu Dec 28 10:08:04 2023 +0800 + + [mem.res.monotonic.buffer.mem] Say `*this` instead of improper `this` + + commit 6ecda0b20664fc6b8450157e1cd9f0580c32e5e1 + Author: A. Jiang + Date: Thu Dec 28 10:09:08 2023 +0800 + + [re.traits] Say `*this` instead of improper `this` + + commit 9305893dfd250d876edf4555cf96c665e2e71e75 + Author: Casey Carter + Date: Thu Feb 15 13:16:33 2024 -0800 + + [thread.once.callonce] INVOKE is evaluated, not called (#6810) + + commit 3616a40ded794e94181a5405672b1c36f7774684 + Author: Jan Schultke + Date: Wed Feb 21 19:05:13 2024 +0100 + + [temp.pre] Add comma after introductory clause (#6814) + + commit 30debb0c5d5dc42fa36864aac76b82f49319ad84 + Author: Jens Maurer + Date: Wed Feb 21 21:39:56 2024 +0100 + + [temp.constr.order] Move index entry to correct paragraph (#6812) + + commit fb0277664fd53efea93d95202784f78aea610f31 + Author: Jan Schultke + Date: Thu Feb 22 20:28:15 2024 +0100 + + [semaphore.syn] Add binary_semaphore to index (#6781) + + commit 090840673ee58d3c1e8d2844d3c716ee5ce245bc + Author: Jan Schultke + Date: Thu Feb 22 20:31:19 2024 +0100 + + [format.parse.ctx] Improve readability of paragraphs 12 and 14 (#6815) + + commit a5825b1905b06d730a46e64fb5b379f48cbc6e51 + Author: Jan Schultke + Date: Thu Feb 22 20:33:18 2024 +0100 + + [format.parse.ctx] Add comma (#6817) + + commit 8c8e05d7ff6cda6329ca898e7a270547a85675d7 + Author: Jan Schultke + Date: Thu Feb 22 20:35:21 2024 +0100 + + [format.parse.ctx] Move non-normative explanations of errors into notes (#6816) + + commit 48f90026631638c91b3d8138bed49cd0450380c7 + Author: Eisenwave + Date: Wed Feb 28 10:23:51 2024 +0100 + + [stmt.while] Add comma after introductory phrase + + commit d5ad3794937429b1410071037af9ddfb0aa8c861 + Author: Eisenwave + Date: Wed Feb 28 10:24:26 2024 +0100 + + [stmt.do] Add comma after introductory phrase + + commit 78ecd23f22f00be4bffaf806a6747417ce2150a2 + Author: Jan Schultke + Date: Wed Feb 28 18:06:26 2024 +0100 + + [stmt.jump] Add cross-reference to [stmt.dcl] for destruction of local variables (#6829) + + commit 66b6b97c8f3969f96e3ca8df1180c18b1c57af8c + Author: Jan Schultke + Date: Wed Feb 28 21:50:50 2024 +0100 + + [expr.dynamic.cast] Add comma after conditional clause (#6830) + + commit 23430d7e605d62f5a4a1769611e3c415d6510b65 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Mar 1 11:06:34 2024 +0100 + + [bibliography] Replace HTTP link with HTTPS link (#6831) + + commit 20c2851a3c8f480a017cef6602b1b6a4d32bc5e4 + Author: Eisenwave + Date: Fri Mar 1 16:03:04 2024 +0100 + + [time.parse] Hyphenate argument-dependent lookup + + commit e0287d17110f86e3724bda5ebe74de249508490f + Author: Eisenwave + Date: Fri Mar 1 16:04:02 2024 +0100 + + [diff.cpp17.temp] Hyphenate argument-dependent lookup + + commit ceff4ea83b511be01a8e1756386ce6a2e06e323c + Author: Jan Schultke + Date: Fri Mar 1 18:06:00 2024 +0100 + + [headers] Strike incorrect quote of subclause heading (#6832) + + commit 9878cfbea12b517d32c5af1bbfa7c8b8c4ff9cab + Author: Jan Schultke + Date: Sun Mar 3 08:42:45 2024 +0100 + + [handler.functions] Add cross-reference to [intro.races] (#6845) + + commit 9ec133c8e51aae98297255563250a2f6656e4636 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Tue Mar 19 15:36:51 2024 +0000 + + [time.hash] Fix spelling of 'Cpp17Hash' + + commit 2b7cd6e8be2bc8a9ae97da9bf03ae4efa7fe1a9c + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Apr 16 20:03:29 2024 +0800 + + [expos.only.entity] Add/fix \expos for exposition-only names (#6924) + + commit aa21c812f629975d5d25d4639053482f346751a8 + Author: Arthur O'Dwyer + Date: Tue Apr 16 08:07:44 2024 -0400 + + [dcl.type.elab] Move note to separate paragraph + + Also clarify that the next paragraph is talking about any elaborated-type-specifier at all, not just the ones in p4. + + commit 397384c90e3ead9f832a3a269335fbfe53328180 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Feb 16 06:51:03 2024 +0100 + + [rand.adapt.ibits,rand.dist.pois.poisson] Add namespace std in class template + + [rand.adapt.ibits] 28.5.5.3-4 + [rand.dist.pois.poisson] 28.5.9.4.1-1 + + commit fbf3d76683d269a0a5313fb69b5aa483ddd3a18a + Author: Jan Schultke + Date: Thu Feb 22 21:41:42 2024 +0100 + + [expr.unary.op] remove redundant value category wording + + commit 498cd7720bb2e53fb323144f956e67900a054e34 + Author: Daniel Krügler + Date: Sun Feb 4 17:57:38 2024 +0100 + + [iterator.requirements.general] Clarify that "constexpr iterator" is a requirement to be met + + [iterator.requirements.general] p16 says "Iterators are called _constexpr iterators_ [..]", but all referencing sections say "meet the constexpr iterator requirements". For clarity, we should reword the definition to make it clear that this is a named requirement. + + commit 89cd1467f354a2b9b05ac57ad1f90f483aab22b9 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sun Jan 28 13:54:17 2024 +0800 + + [range.drop.overview] Remove redundant \iref for subrange + + ..which already existed in the previous bullet. + + commit bee055de1c5e23ce0b301138998633dc64169b4a + Author: A. Jiang + Date: Thu Nov 23 09:33:39 2023 +0800 + + [dcl.init.ref] Change "function lvalue" to "lvalue of function type" + + commit ce31d424ba6753be1c87a4cf3face42f89b9e010 + Author: A. Jiang + Date: Thu Nov 23 09:36:28 2023 +0800 + + [over.ics.ref] Simplify wording by not using "function lvalue" + + commit 2a07c133732dcc7ea57aeb32612b15b50837a4df + Author: A. Jiang + Date: Thu Nov 23 09:38:41 2023 +0800 + + [over.ics.rank] Change "function lvalue" to "lvalue of function type" + + commit 7675c4c1abf1986241e8a20463fd71f2841d3c39 + Author: Eisenwave + Date: Fri Sep 1 10:27:25 2023 +0200 + + [res.on.exception.handling] use grammarterm instead of informal term and add ref diff --git a/papers/n4987.html b/papers/n4987.html new file mode 100644 index 0000000000..3099e7e867 --- /dev/null +++ b/papers/n4987.html @@ -0,0 +1,915 @@ + + + + + +N4987 + + +

N4987 Editors’ Report:
Programming Languages — C++

+ +

Date: 2024-07-16

+ +

Thomas Köppe (editor, Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor, Bright Side Computing, LLC)
+Richard Smith (co-editor, Google Inc)

+ +

Email: cxxeditor@gmail.com

+ +

Acknowledgements

+ +

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

+ +

New papers

+ +
    +
  • N4986 is the +current working draft for C++26. It replaces +N4981.
  • +
  • N4987 is this Editors' Report.
  • +
+ +

Motions incorporated into working draft

+ +

Notes on motions

+ +

All passed motions from CWG and LWG motions 1 through 9 were applied cleanly. +LWG motions 10, 11, and 12 have not yet been applied due to a lack of time, +but will be included in the next draft.

+ +

In CWG Poll 1, issue CWG2144 contains no wording changes since it is subsumed by CWG2876, which is part of Poll 2. +The wording changes from issue CWG2867 of CWG Poll 1 affect the same wording as CWG Poll 7; the wording has been reconciled.

+ +

Core working group polls

+ +

CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues except 2819, 2858, and 2876 in +P3345R0 +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper.

+ +

CWG Poll 2. Apply the proposed resolution of issues 2819, 2858, and 2876 in +P3345R0 +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper.

+ +

CWG Poll 3. Apply the changes in +P2747R2 +(constexpr placement new) to the C++ Working Paper.

+ +

CWG Poll 5. Apply the changes in +P3144R2 +(Deleting a Pointer to an Incomplete Type Should be Ill-formed) to the C++ Working Paper.

+ +

CWG Poll 6. Apply the changes in +P2963R3 +(Ordering of constraints involving fold expressions) to the C++ Working Paper.

+ +

CWG Poll 7. Apply the changes in +P0963R3 +(Structured binding declaration as a condition) to the C++ Working Paper.

+ +

CWG Poll 4 did not have consensus.

+ +

Library working group polls

+ +

LWG Poll 1. Apply the changes for all Ready and Tentatively Ready issues in +P3341R0 +(C++ Standard Library Ready Issues to be moved in St. Louis, Jun. 2024) to the C++ working paper.

+ +

LWG Poll 2. Apply the changes in +P2997R1 +(Removing the common reference requirement from the indirectly invocable concepts) to the C++ working paper.

+ +

LWG Poll 3. Apply the changes in +P2389R2 +(dextents Index Type Parameter) to the C++ working paper.

+ +

LWG Poll 4. Apply the changes in +P3168R2 +(Give std::optional Range Support) to the C++ working paper.

+ +

LWG Poll 5. Apply the changes in +P3217R0 +(Adjoints to "Enabling list-initialization for algorithms": find_last) to the C++ working paper.

+ +

LWG Poll 6. Apply the changes in +P2985R0 +(A type trait for detecting virtual base classes) to the C++ working paper.

+ +

LWG Poll 7. Apply the changes in +P0843R14 +(inplace_vector) to the C++ working paper.

+ +

LWG Poll 8. Accept as a Defect Report and apply the changes in +P3235R3 +(std::print more types faster with less memory) to the C++ working paper.

+ +

LWG Poll 9. Apply the changes in +P2968R2 +(Make std::ignore a first-class object) to the C++ working paper.

+ +

Not yet applied:

+ +

LWG Poll 10. Apply the changes in +P2075R6 +(Philox as an extension of the C++ RNG engines) to the C++ working paper.

+ +

LWG Poll 11. Apply the changes in +P2422R1 +(Remove nodiscard annotations from the standard library specification) to the C++ working paper.

+ +

LWG Poll 12. Apply the changes in +P2300R10 +(std::execution) to the C++ working paper.

+ +

Editorial changes

+ +

Major editorial changes

+ +

A number of editorial changes have been applied that resulted from the ongoing review of the +C++23 IS with the ISO secretariat.

+ +

Mathematical formulae are now numbered, and they must be referenced explicitly from the text.

+ +

We avoid writing references as "subclause 1.2.3" in favour of just "1.2.3" now whenever that is +equally clear.

+ +

Examples in Annex C now use the regular example style, as opposed to the previous ad-hoc style.

+ +

We changed how we refer to the C++ standard itself and how we cite other standards. The page +footers have been changed to show the page number and the copyright over two lines, and the +display of Annex titles has been changed, both in accordance with new ISO style advice. For +details see the following listing.

+ +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N4981 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 59d6bfc0c23b61cabb72d9a48270ed1c3b7e02f9
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Apr 16 09:57:19 2024 -0400
+
+    [basic.life] Reflow text defining transparently replaceable
+
+    p8 is difficult to read as it defines transparently replaceable
+    only after it has made all use of it.  The edit pulls the
+    definition of transparently replaceable into its own preceding
+    paragraph, and then simplifies the sentence that uses this term.
+
+commit ccfb6adea4373a63b7063f4d41cb9d47876a9347
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Apr 17 03:08:36 2024 -0400
+
+    [tab:headers.cpp.fs] Move the debugging library to numberically sorted position (#6927)
+
+commit c82e95ca91b313bc2cfde60aac9abbd49406d930
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Apr 17 18:42:19 2024 -0400
+
+    [zombie.names] Turn lists of zombie names into tables (#6925)
+
+commit c1eec01966d6383dabfaa4304939ce3be3868f1f
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Thu Apr 18 23:51:53 2024 +0800
+
+    [range.concat.overview] Remove unnecessary `std::` prefix from example (#6931)
+
+commit 2de15529d3f98a5de25cecf9ac8ed5b104d776e1
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Apr 18 18:00:42 2024 +0200
+
+    [charconv.syn] Clarify types matching integer-type (#6847)
+
+commit bae18b69cbca566eac284c8c2f316407fda98d16
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Apr 19 01:21:19 2024 +0800
+
+    [range.concat.view] Format code to match the current style (#6929)
+
+commit 79dcca82c22d75fc2b2b6cbc1c338a0229db9a34
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Fri Apr 19 19:51:29 2024 +0800
+
+    [range.utility.conv.general] Fix misapplication of LWG4016 (#6932)
+
+commit e572580d71dfc8bdb32b8d1a21a2e493676e2151
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Apr 19 21:57:48 2024 +0800
+
+    [range.concat.iterator] Remove @ outside of codeblocks (#6934)
+
+commit 5a5295d9c9e1881e58d3b4696fe45f00ef1cc507
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Fri Apr 19 17:32:53 2024 -0400
+
+    [index] Add missing entries for Cpp17 concepts (#6940)
+
+commit 5d4d9508bca4709366a0ff7acb17ba7b3a2efced
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sat Apr 20 20:16:23 2024 +0800
+
+    [range.join.with.iterator] Add missing 'template' keyword for dependent name 'emplace' (#5455)
+
+commit 0ac38fd4c4548ff61cd378f98eff3e18f4463caf
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Fri Aug 18 15:12:08 2023 +0800
+
+    Fix typo (`dynamic_rank` => `rank_dynamic`)
+
+commit 47c2f68d84cb13a7ca83a507fb1f32ddf4774ec1
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Mon Apr 22 23:19:41 2024 +0200
+
+    [mdspan.layout.leftpad.obs] Remove superfluous \item (#6944)
+
+commit 4f0779d5a3665af9dd92a96e52d809ba3911495d
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Tue Apr 23 12:13:27 2024 +0200
+
+    [intro.execution] Add comma after conditional clause (#6945)
+
+commit 12b6307589257a803527eb38c43f08f867d59322
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Apr 29 15:23:41 2024 +0800
+
+    [algorithm.syn,alg.fill] Fix typos in constraints (#6957)
+
+commit 927d0dba2b068ba9f2136479b4ba05a430eec348
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Apr 29 22:43:49 2024 +0800
+
+    [alg.rand.generate] Remove brace typo (#6956)
+
+commit 480adbe4d6ae54e03b6cec5f8784689445c36eee
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Apr 30 07:48:14 2024 +0200
+
+    [print.syn] Correctly order println overloads
+
+commit 3333421819c1b2c6dec1becd0dd2a9fa0aeba8cd
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Apr 30 20:22:43 2024 +0800
+
+    [range.concat.iterator] Remove superfluous period (#6960)
+
+commit 513635b371c6a664be2a0ea6fc6939350b9b5e6b
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri May 10 00:17:43 2024 +0800
+
+    [range.reverse.overview] Replace 'equivalent to' with 'then' (#6966)
+
+commit be18ecc17114bcae4acdad10a3467686510b22c2
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat May 11 21:51:48 2024 +0200
+
+    [class.derived.general] Restore accidental reversal of P2662R3 change
+
+    P2662R3 contained a rename of the grammar production "class-or-decltype"
+    to "class-or-computed-type-specifier".  That was editorially reverted
+    with commit c831ec0b8aac369aa61ce392783865ff04b84b19, but that commit
+    also accidentally reverted the change from "decltype-specifier" to
+    "computed-type-specifier" as one of the options for "class-or-decltype".
+
+    This commit restores the latter change, as intended by P2662R3.
+
+commit 9dcff41d2d26577c2ec0643056187a0f8094832e
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun May 12 15:24:43 2024 +0100
+
+    [intro.refs] Fix document titles
+
+commit 5b332fed1a4577ad08ed469da26c9c7864ea9e11
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun May 12 15:31:43 2024 +0100
+
+    [intro.refs, intro.defs] Update ISO 80000-2:2009 to :2019, change "and" to comma
+
+commit 85f4bb454effe50029de636d6f206f9c1153236a
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun May 12 15:53:11 2024 +0100
+
+    [defns.order.ptr] Add missing hypen in "built-in"
+
+commit 9cd8d6ce9cc446c94d91e1350b9113906774f0af
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue May 14 21:49:55 2024 +0800
+
+    [format.context] Fix error in example (#6970)
+
+commit 951ded4880e4295981c0d691915a81d84c2baa9d
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun May 12 16:01:09 2024 +0100
+
+    [defns.unblock] Italicize entire term "blocked", not just "block".
+
+    ISO has indicated that this is the acceptable way to state a reference to another definition, in this case "block" [defns.block].
+
+commit 1cb3842f83412720a23c664f478a4167cb3162a2
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue May 14 18:52:30 2024 +0200
+
+    [styles] Redesign Annex titles per Rice Model Standard
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 2f23560744a966f7a455629506468a02055d53ea
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Mon May 20 05:52:26 2024 -0400
+
+    [alg.ends.with] Replace drop_view with views::drop (#6773)
+
+commit bbac8a98d303d3ad5ecd9514fb2db37745d16984
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Mon May 20 07:24:27 2024 -0400
+
+    [dcl.init.list] Eliminate "specialization of initializer_list<X>" (#6258)
+
+commit ad37b863dec4af4c88d8f2154d5f3e4a9b2a3b33
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Tue May 21 07:12:32 2024 -0400
+
+    [support.initlist] "initializer list" should be "initializer_list" (#6680)
+
+    This note is talking about the class type, not the grammatical construct.
+
+commit 2e455af5d6a2bdaac7e9d0d4e7f23ac7a6c0451d
+Author: zhihaoy <43971430+zhihaoy@users.noreply.github.com>
+Date:   Tue May 21 22:50:56 2024 -0700
+
+    [util.smartptr.shared.cast] Properly describe possibility of double deletion in notes (#7037)
+
+commit 4b3f32ae814c8da3faccc0dc307904bd250371d9
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue May 28 22:10:36 2024 +0100
+
+    [input.output] Add cross-references to header synopses (#7005)
+
+    Several of the synopses are not adjacent to the types they declare.
+    Adding cross-references makes it easier to find the relevant definitions
+    of classes and class templates.
+
+    Also make the title of [ostream.manip] more specific to its content.
+
+commit dbf17528619707307f859bac1b36c52654fecfc8
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Mon Jun 10 17:06:15 2024 -0400
+
+    [container.adaptors] Reorder constructors for flat_* adaptors (#6274)
+
+    Canonicalize the ordering of the constructors for the flat_* adaptors:
+     - default constructor is first
+     - each overload without `key_compare` is followed by the corresponding one with `key_compare`
+     - each pair of overloads without `sorted_unique` is followed by the corresponding pair with `sorted_unique`
+
+commit ae9b2d7481af415076ffdf33d5920e31e5591eb1
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Tue Jun 11 15:32:36 2024 +0200
+
+    [res.on.exception.handling] Add cross-reference to [except.spec] (#7058)
+
+commit c95ff039b634388962e1fa242e772da8466d49b6
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Wed Jun 12 12:36:02 2024 +0200
+
+    [stmt.if] Add missing comma after conditional clause (#7061)
+
+commit 42a38b072a471a112720535c087d96c8f4865a47
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Wed Jun 12 18:56:14 2024 +0200
+
+    [stmt.pre] Add a cross-reference to [intro.execution] (#7060)
+
+commit 3680e10a5a7eb48b35f150429ce6b3313583bb87
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Fri Jun 14 12:48:46 2024 +0200
+
+    [class.virtual] Add commas (#7062)
+
+commit 9ad7d63f8db28c88dfa68866d23c5ab742be3f80
+Author: Antony Polukhin <antoshkka@gmail.com>
+Date:   Tue Jun 18 19:00:34 2024 +0300
+
+    [associative.reqmts.general] Fix typo (#7069)
+
+commit a24620eced94b1f04fcbd8add49f5e9ca6326ed4
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Jun 21 12:36:01 2024 +0200
+
+    [class.union.general] Add comma (#7072)
+
+commit 59e634a8a841f58efeac873459bedf28928a83f9
+Author: Johannes Sixt <j6t@kdbg.org>
+Date:   Wed Jun 26 11:53:47 2024 +0200
+
+    [func.require] Add missing formatting of subscript index (#7071)
+
+commit 6d67d200863e430650047adb651324bc5663b6fc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue May 14 13:13:42 2024 +0200
+
+    [diff] Mark examples as such
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 21e022557462544e2e6d32411f71e42a378d2236
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue Jul 2 14:31:08 2024 +0100
+
+    [depr.c.macros] Fix "macro" singular when referring to two macros
+
+    This should have been applied as part of LWG 4036.
+
+commit 8bb63636c37f8e67808de1e1ce1142a3028293fd
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed Jul 3 20:53:40 2024 +0100
+
+    [istream.unformatted] add missing semi-colon to list item (#7117)
+
+commit 8227c196af96f157a539e5181f7a75ab3de3a096
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Jul 5 10:03:47 2024 +0200
+
+    [except.throw] Add comma (#7118)
+
+commit 07c20b75a867b66c858de716dfb639b0a9d1da2c
+Author: Yihe Li <winmikedows@hotmail.com>
+Date:   Sat Jul 6 23:32:43 2024 +0800
+
+    [version.syn] Remove redundant <version> for __cpp_lib_ranges_enumerate (#7120)
+
+commit 15b7ea6c95e471888cda2c334ba8ac30cabccf64
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sun Jul 7 10:23:09 2024 +0200
+
+    [basic.start.main] fix definite article (#7121)
+
+commit 61d85d3f9b78d792bd1bdb1d15202f9cdd931b31
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 9 00:57:58 2024 +0100
+
+    [intro.compliance.general] Cite Annex B more normatively.
+
+commit 2048179f82bbe92dcccee3cc6bbdac4973c77606
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 9 01:25:28 2024 +0100
+
+    [intro.compliance.general] Cite Annex D more normatively.
+
+commit 6b67a856495634df3a0bd0d8abee36eb0d3c8c6f
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Jul 9 08:29:50 2024 +0200
+
+    [temp.inst] Fix definite article
+
+commit 43c47b42fd1f7cd4d095299aca98666c06e45949
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 9 01:44:08 2024 +0100
+
+    [uaxid] Clarify that requirements come "from UAX #31", and use "this document".
+
+commit 7c35cb057ef4885e091bf65c1103d64946e7c8d1
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 9 14:47:10 2024 +0100
+
+    [std] Make bibliography reference link colour more citely
+
+commit bc2c80c23133a0581a847bd7fcfaca621ca86ffe
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 20:17:21 2024 +0200
+
+    [dcl.init.list] Add commas and period for bulleted list
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 868db7356ad1490890391e8c82888de5c4d4aad4
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 20:18:20 2024 +0200
+
+    [facet.num.get.virtuals] Add missing punctuation
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 77ee6ed3b8865b2bb514cb8446488aa6fb032dda
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 23:39:13 2024 +0200
+
+    [lex.literal] Properly format table headings
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit cb9850377b88a4d7da12d05bcdf11948c384f699
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 23:47:55 2024 +0200
+
+    [basic.fundamental] Center second column of "integer width" table
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 2a2b8732e0d81dd9f5d3880b70bd451173e5f5fc
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 9 15:41:56 2024 +0100
+
+    [intro.defs] Minor rewording. Avoid sounding like a requirement.
+
+commit 4746925c7117015480542fd68ad5f595b78173d2
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue May 14 14:11:53 2024 +0200
+
+    [numeric.limits.members,bibliography] Remove LIA-1 abbreviation for ISO 10967
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit c18d51ddf436abf39065ea86497161383bba11c0
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 15 09:05:36 2024 +0200
+
+    [intro.memory] Move footnote about Unicode trademark to [lex.phases]
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 1f32f6aa8000f194f1b5c4daba94d271eea817fb
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 15 16:28:34 2024 +0200
+
+    [diff,bibliography] Move details of old C++ standards to the bibliography
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit d5410b4035e3108d48a63434abfff7e377c996d2
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 15 18:31:14 2024 +0200
+
+    [diff.cpp20,diff.cpp17] Add missing inclusion clause
+
+commit af4cf904c3d2df0675dbd456af2de2f1259e370c
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 16 12:56:12 2024 +0200
+
+    [std] Rename 'In general' headings to 'General' for consistency
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 9d3011b4224bb63636f4a117967e8ba8110f5ba4
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri May 17 14:11:48 2024 +0200
+
+    [implimits] Rephrase introductory sentence for list of quantities
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 260d3a0d0cde1431dd4221115e1b37979ee07e7d
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 16 12:30:44 2024 +0200
+
+    [class.copy.ctor] Remove reference to non-existing example
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 0bc3e030be28ff2191af8e9c9c202bff6e23c320
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 16 12:37:12 2024 +0200
+
+    [class.conv.general] Remove vague reference to unhelpful examples
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 861f07de24c5cfbd69840038d8589bc13b24b7e7
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 15 21:58:36 2024 +0200
+
+    [cpp.predefined,namespace.future,version.syn] Replace 'C++' with 'this document'
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit a7a2cbd10ea752d49ca286e3fea3e7cbbb9b6e9d
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri May 17 00:44:32 2024 +0200
+
+    [futures.state] Turn note into example
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 88c48bb78815576fb20db42b89f381c580d28b0e
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue May 14 22:41:24 2024 +0200
+
+    [std] Remove colons in front of bulleted lists
+
+commit 9d7aa6108b84a09117463d0b13bc24cf61926897
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue May 14 22:47:38 2024 +0200
+
+    [iterators] Add colon after 'model ... only if' when complete sentences follow
+
+commit 79ac47f7053da4ef20c117e282377591d028e7a5
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 15 21:42:09 2024 +0200
+
+    [basic.fundamental,cstdarg.syn] Use full reference for ISO C sections
+
+    Fixes ISO/CS comment (C++23)
+
+commit 2bbf136502811925250b09fd73909b78e0236091
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 16 12:51:32 2024 +0200
+
+    [execpol.general] Use 'this document', not 'this standard'
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit e65393f3c87d323258e38c498b849dc57404a20b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 15 22:13:14 2024 +0200
+
+    [format.string.std] Add (R) symbol after Windows
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit dafefea895de358b8edcb6780e3c7b71d209b458
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue May 14 19:12:57 2024 +0200
+
+    [rand.req] Replace 'that Table' with a precise reference
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 361e7769a245aad263574bbe83b9266d8da3b01b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri May 17 09:42:22 2024 +0200
+
+    [std] Replace 'this standard' with 'this document'
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit e86031dd14e052956fc23ec4dbc1510b7438ba5b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 23:19:57 2024 +0200
+
+    [time.format,time.parse] Fix references to ISO week calendar
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 868b0b29ac16370ed8792442a0ab41be91c5d575
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 19:01:05 2024 +0200
+
+    [std] Avoid hanging paragraphs by introducing "General" subclauses
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit f0580700cf0e8e920ceb3a078b6872a4c16fa225
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 15 21:49:31 2024 +0200
+
+    [std] Remove ISO from any mention of 'C'
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 69f184ea599635dac4cd9dc06a3303bed93b26f7
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 19:30:38 2024 +0200
+
+    [std] Remove mid-sentence 'subclause' introducer
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit ecb071672b02a4b7bc829f87433d98785d9dd701
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon May 13 19:44:40 2024 +0200
+
+    [std] Remove incorrect or duplicative 'this subclause' introducers
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit a249f9f37531fe79e768f19a45f1b1a70685c2c6
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 9 22:48:20 2024 +0100
+
+    [classes] Turn ad-hoc examples into proper examples (#7125)
+
+commit eade3851e174ac014b478b8d4f097103d3b996ae
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 16 12:44:01 2024 +0200
+
+    [lex.ccon,expr.prim.lambda.capture] Excise 'ISO' prefix
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 5383169856690cf05d946f058ed861119405d126
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 16 14:32:49 2024 +0200
+
+    [fs.class.path.general] Defuse cross-reference to POSIX
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 5731ab6a9122763bf6193d1382a05c7bebe82b38
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 9 23:24:09 2024 +0100
+
+    [time.format] Remove mid-sentence 'subclause' introducer from external reference
+
+commit 856d175973d343d8e16d641221f47357672d9959
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri May 17 14:26:54 2024 +0200
+
+    [lib] Excise Note A, Note B, etc. designations
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 5508a007540d790a8f5cd30f863f4d329edf2694
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 16 15:07:27 2024 +0200
+
+    [macros,numerics] Add and use numbered 'formula' environment
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 2b0ff8d6bd285bbe8b27fdab47e268b115a3f930
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Jul 10 11:33:23 2024 +0100
+
+    [lex.string] Replace colon with full stop to end the sentence.
+
+    On request of ISO/CS, for otherwise we should have made the next 'if'
+    lowercase, because: "Grammatically this is the same sentence,
+    as there is no full stop, so the 'if' should be lowercase."
+
+    If a colon really doesn't end a sentence, then we should make it so
+    that the sentence really does end.
+
+commit 064fb0b34eb8cbb14f52dc966c833ef7c749c82c
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue May 14 08:23:07 2024 +0200
+
+    [macros] Prefer page break above 'note' or 'example' introducers
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 13b08d0f58dfea7ae2e19b1d931094d4523a52d2
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Jul 11 01:41:29 2024 +0100
+
+    [layout, styles] New ISO header and footer layout.
+
+    The footer now takes up two lines, one for the copyright and one for
+    the page number.
+
+commit 7f6069c794abb56e51affdc2923e3d33b3a547a8
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Jul 11 12:27:28 2024 +0100
+
+    [cover-reg] Update regular cover
+
+commit f41a619cf852ae638bfe4792ec78ac1f214a7d23
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Jul 12 01:28:38 2024 +0100
+
+    [impldefindex] Reinstate full page mark
+
+    As of 13b08d0f58dfea7ae2e19b1d931094d4523a52d2 we have space for it.
+
+commit b2870b5c87765946f5c4a644da508adcc483045e
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Jul 12 01:30:06 2024 +0100
+
+    [macros, std] Create macros for ISO/IEC 60559 and ISO/IEC/IEEE 9945.
+
+    As a side effect, this corrects the title of ISO/IEC 60559(:2020),
+    whose previous version was ISO/IEC/IEEE 60559:2011.
+
+ + diff --git a/papers/n4987.md b/papers/n4987.md new file mode 100644 index 0000000000..d405f0b427 --- /dev/null +++ b/papers/n4987.md @@ -0,0 +1,774 @@ +# N4987 Editors' Report -- Programming Languages -- C++ + +Date: 2024-07-16 + +Thomas Köppe (editor, Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor, Bright Side Computing, LLC) +Richard Smith (co-editor, Google Inc) + +Email: `cxxeditor@gmail.com` + +## Acknowledgements + +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 + + * [N4986](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4986.pdf) is the + current working draft for C++26. It replaces + [N4981](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4981.pdf). + * N4987 is this Editors' Report. + +## Motions incorporated into working draft + +### Notes on motions + +All passed motions from CWG and LWG motions 1 through 9 were applied cleanly. +LWG motions 10, 11, and 12 have not yet been applied due to a lack of time, +but will be included in the next draft. + +In CWG Poll 1, issue CWG2144 contains no wording changes since it is subsumed by CWG2876, which is part of Poll 2. +The wording changes from issue CWG2867 of CWG Poll 1 affect the same wording as CWG Poll 7; the wording has been reconciled. + +### Core working group polls + +CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues except 2819, 2858, and 2876 in +[P3345R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3345r0.html) +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper. + +CWG Poll 2. Apply the proposed resolution of issues 2819, 2858, and 2876 in +[P3345R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3345r0.html) +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper. + +CWG Poll 3. Apply the changes in +[P2747R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html) +(`constexpr` placement new) to the C++ Working Paper. + +CWG Poll 5. Apply the changes in +[P3144R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3144r2.pdf) +(Deleting a Pointer to an Incomplete Type Should be Ill-formed) to the C++ Working Paper. + +CWG Poll 6. Apply the changes in +[P2963R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2963r3.pdf) +(Ordering of constraints involving fold expressions) to the C++ Working Paper. + +CWG Poll 7. Apply the changes in +[P0963R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0963r3.html) +(Structured binding declaration as a condition) to the C++ Working Paper. + +CWG Poll 4 did not have consensus. + +### Library working group polls + +LWG Poll 1. Apply the changes for all Ready and Tentatively Ready issues in +[P3341R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3341r0.html) +(C++ Standard Library Ready Issues to be moved in St. Louis, Jun. 2024) to the C++ working paper. + +LWG Poll 2. Apply the changes in +[P2997R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2997r1.html) +(Removing the common reference requirement from the indirectly invocable concepts) to the C++ working paper. + +LWG Poll 3. Apply the changes in +[P2389R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2389r2.html) +(`dextents` Index Type Parameter) to the C++ working paper. + +LWG Poll 4. Apply the changes in +[P3168R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3168r2.html) +(Give `std::optional` Range Support) to the C++ working paper. + +LWG Poll 5. Apply the changes in +[P3217R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3217r0.html) +(Adjoints to "Enabling list-initialization for algorithms": `find_last`) to the C++ working paper. + +LWG Poll 6. Apply the changes in +[P2985R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2985r0.html) +(A type trait for detecting virtual base classes) to the C++ working paper. + +LWG Poll 7. Apply the changes in +[P0843R14](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0843r14.html) +(`inplace_vector`) to the C++ working paper. + +LWG Poll 8. Accept as a Defect Report and apply the changes in +[P3235R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3235r3.html) +(std::print more types faster with less memory) to the C++ working paper. + +LWG Poll 9. Apply the changes in +[P2968R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2968r2.html) +(Make std::ignore a first-class object) to the C++ working paper. + +**Not yet applied:** + +LWG Poll 10. Apply the changes in +[P2075R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2075r6.html) +(Philox as an extension of the C++ RNG engines) to the C++ working paper. + +LWG Poll 11. Apply the changes in +[P2422R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2422r1.html) +(Remove nodiscard annotations from the standard library specification) to the C++ working paper. + +LWG Poll 12. Apply the changes in +[P2300R10](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html) +(std::execution) to the C++ working paper. + +## Editorial changes + +### Major editorial changes + +A number of editorial changes have been applied that resulted from the ongoing review of the +C++23 IS with the ISO secretariat. + +Mathematical formulae are now numbered, and they must be referenced explicitly from the text. + +We avoid writing references as "subclause 1.2.3" in favour of just "1.2.3" now whenever that is +equally clear. + +Examples in Annex C now use the regular example style, as opposed to the previous ad-hoc style. + +We changed how we refer to the C++ standard itself and how we cite other standards. The page +footers have been changed to show the page number and the copyright over two lines, and the +display of Annex titles has been changed, both in accordance with new ISO style advice. For +details see the following listing. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N4981 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/n4981...n4986). + + commit 59d6bfc0c23b61cabb72d9a48270ed1c3b7e02f9 + Author: Alisdair Meredith + Date: Tue Apr 16 09:57:19 2024 -0400 + + [basic.life] Reflow text defining transparently replaceable + + p8 is difficult to read as it defines transparently replaceable + only after it has made all use of it. The edit pulls the + definition of transparently replaceable into its own preceding + paragraph, and then simplifies the sentence that uses this term. + + commit ccfb6adea4373a63b7063f4d41cb9d47876a9347 + Author: Alisdair Meredith + Date: Wed Apr 17 03:08:36 2024 -0400 + + [tab:headers.cpp.fs] Move the debugging library to numberically sorted position (#6927) + + commit c82e95ca91b313bc2cfde60aac9abbd49406d930 + Author: Alisdair Meredith + Date: Wed Apr 17 18:42:19 2024 -0400 + + [zombie.names] Turn lists of zombie names into tables (#6925) + + commit c1eec01966d6383dabfaa4304939ce3be3868f1f + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Thu Apr 18 23:51:53 2024 +0800 + + [range.concat.overview] Remove unnecessary `std::` prefix from example (#6931) + + commit 2de15529d3f98a5de25cecf9ac8ed5b104d776e1 + Author: Jan Schultke + Date: Thu Apr 18 18:00:42 2024 +0200 + + [charconv.syn] Clarify types matching integer-type (#6847) + + commit bae18b69cbca566eac284c8c2f316407fda98d16 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Apr 19 01:21:19 2024 +0800 + + [range.concat.view] Format code to match the current style (#6929) + + commit 79dcca82c22d75fc2b2b6cbc1c338a0229db9a34 + Author: S. B. Tam + Date: Fri Apr 19 19:51:29 2024 +0800 + + [range.utility.conv.general] Fix misapplication of LWG4016 (#6932) + + commit e572580d71dfc8bdb32b8d1a21a2e493676e2151 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Apr 19 21:57:48 2024 +0800 + + [range.concat.iterator] Remove @ outside of codeblocks (#6934) + + commit 5a5295d9c9e1881e58d3b4696fe45f00ef1cc507 + Author: Alisdair Meredith + Date: Fri Apr 19 17:32:53 2024 -0400 + + [index] Add missing entries for Cpp17 concepts (#6940) + + commit 5d4d9508bca4709366a0ff7acb17ba7b3a2efced + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sat Apr 20 20:16:23 2024 +0800 + + [range.join.with.iterator] Add missing 'template' keyword for dependent name 'emplace' (#5455) + + commit 0ac38fd4c4548ff61cd378f98eff3e18f4463caf + Author: S. B. Tam + Date: Fri Aug 18 15:12:08 2023 +0800 + + Fix typo (`dynamic_rank` => `rank_dynamic`) + + commit 47c2f68d84cb13a7ca83a507fb1f32ddf4774ec1 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Mon Apr 22 23:19:41 2024 +0200 + + [mdspan.layout.leftpad.obs] Remove superfluous \item (#6944) + + commit 4f0779d5a3665af9dd92a96e52d809ba3911495d + Author: Jan Schultke + Date: Tue Apr 23 12:13:27 2024 +0200 + + [intro.execution] Add comma after conditional clause (#6945) + + commit 12b6307589257a803527eb38c43f08f867d59322 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Apr 29 15:23:41 2024 +0800 + + [algorithm.syn,alg.fill] Fix typos in constraints (#6957) + + commit 927d0dba2b068ba9f2136479b4ba05a430eec348 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Apr 29 22:43:49 2024 +0800 + + [alg.rand.generate] Remove brace typo (#6956) + + commit 480adbe4d6ae54e03b6cec5f8784689445c36eee + Author: Jens Maurer + Date: Tue Apr 30 07:48:14 2024 +0200 + + [print.syn] Correctly order println overloads + + commit 3333421819c1b2c6dec1becd0dd2a9fa0aeba8cd + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Apr 30 20:22:43 2024 +0800 + + [range.concat.iterator] Remove superfluous period (#6960) + + commit 513635b371c6a664be2a0ea6fc6939350b9b5e6b + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri May 10 00:17:43 2024 +0800 + + [range.reverse.overview] Replace 'equivalent to' with 'then' (#6966) + + commit be18ecc17114bcae4acdad10a3467686510b22c2 + Author: Jens Maurer + Date: Sat May 11 21:51:48 2024 +0200 + + [class.derived.general] Restore accidental reversal of P2662R3 change + + P2662R3 contained a rename of the grammar production "class-or-decltype" + to "class-or-computed-type-specifier". That was editorially reverted + with commit c831ec0b8aac369aa61ce392783865ff04b84b19, but that commit + also accidentally reverted the change from "decltype-specifier" to + "computed-type-specifier" as one of the options for "class-or-decltype". + + This commit restores the latter change, as intended by P2662R3. + + commit 9dcff41d2d26577c2ec0643056187a0f8094832e + Author: Thomas Köppe + Date: Sun May 12 15:24:43 2024 +0100 + + [intro.refs] Fix document titles + + commit 5b332fed1a4577ad08ed469da26c9c7864ea9e11 + Author: Thomas Köppe + Date: Sun May 12 15:31:43 2024 +0100 + + [intro.refs, intro.defs] Update ISO 80000-2:2009 to :2019, change "and" to comma + + commit 85f4bb454effe50029de636d6f206f9c1153236a + Author: Thomas Köppe + Date: Sun May 12 15:53:11 2024 +0100 + + [defns.order.ptr] Add missing hypen in "built-in" + + commit 9cd8d6ce9cc446c94d91e1350b9113906774f0af + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue May 14 21:49:55 2024 +0800 + + [format.context] Fix error in example (#6970) + + commit 951ded4880e4295981c0d691915a81d84c2baa9d + Author: Thomas Köppe + Date: Sun May 12 16:01:09 2024 +0100 + + [defns.unblock] Italicize entire term "blocked", not just "block". + + ISO has indicated that this is the acceptable way to state a reference to another definition, in this case "block" [defns.block]. + + commit 1cb3842f83412720a23c664f478a4167cb3162a2 + Author: Jens Maurer + Date: Tue May 14 18:52:30 2024 +0200 + + [styles] Redesign Annex titles per Rice Model Standard + + Fixes ISO/CS comment (C++23 proof) + + commit 2f23560744a966f7a455629506468a02055d53ea + Author: Arthur O'Dwyer + Date: Mon May 20 05:52:26 2024 -0400 + + [alg.ends.with] Replace drop_view with views::drop (#6773) + + commit bbac8a98d303d3ad5ecd9514fb2db37745d16984 + Author: Arthur O'Dwyer + Date: Mon May 20 07:24:27 2024 -0400 + + [dcl.init.list] Eliminate "specialization of initializer_list" (#6258) + + commit ad37b863dec4af4c88d8f2154d5f3e4a9b2a3b33 + Author: Arthur O'Dwyer + Date: Tue May 21 07:12:32 2024 -0400 + + [support.initlist] "initializer list" should be "initializer_list" (#6680) + + This note is talking about the class type, not the grammatical construct. + + commit 2e455af5d6a2bdaac7e9d0d4e7f23ac7a6c0451d + Author: zhihaoy <43971430+zhihaoy@users.noreply.github.com> + Date: Tue May 21 22:50:56 2024 -0700 + + [util.smartptr.shared.cast] Properly describe possibility of double deletion in notes (#7037) + + commit 4b3f32ae814c8da3faccc0dc307904bd250371d9 + Author: Jonathan Wakely + Date: Tue May 28 22:10:36 2024 +0100 + + [input.output] Add cross-references to header synopses (#7005) + + Several of the synopses are not adjacent to the types they declare. + Adding cross-references makes it easier to find the relevant definitions + of classes and class templates. + + Also make the title of [ostream.manip] more specific to its content. + + commit dbf17528619707307f859bac1b36c52654fecfc8 + Author: Arthur O'Dwyer + Date: Mon Jun 10 17:06:15 2024 -0400 + + [container.adaptors] Reorder constructors for flat_* adaptors (#6274) + + Canonicalize the ordering of the constructors for the flat_* adaptors: + - default constructor is first + - each overload without `key_compare` is followed by the corresponding one with `key_compare` + - each pair of overloads without `sorted_unique` is followed by the corresponding pair with `sorted_unique` + + commit ae9b2d7481af415076ffdf33d5920e31e5591eb1 + Author: Jan Schultke + Date: Tue Jun 11 15:32:36 2024 +0200 + + [res.on.exception.handling] Add cross-reference to [except.spec] (#7058) + + commit c95ff039b634388962e1fa242e772da8466d49b6 + Author: Jan Schultke + Date: Wed Jun 12 12:36:02 2024 +0200 + + [stmt.if] Add missing comma after conditional clause (#7061) + + commit 42a38b072a471a112720535c087d96c8f4865a47 + Author: Jan Schultke + Date: Wed Jun 12 18:56:14 2024 +0200 + + [stmt.pre] Add a cross-reference to [intro.execution] (#7060) + + commit 3680e10a5a7eb48b35f150429ce6b3313583bb87 + Author: Jan Schultke + Date: Fri Jun 14 12:48:46 2024 +0200 + + [class.virtual] Add commas (#7062) + + commit 9ad7d63f8db28c88dfa68866d23c5ab742be3f80 + Author: Antony Polukhin + Date: Tue Jun 18 19:00:34 2024 +0300 + + [associative.reqmts.general] Fix typo (#7069) + + commit a24620eced94b1f04fcbd8add49f5e9ca6326ed4 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Jun 21 12:36:01 2024 +0200 + + [class.union.general] Add comma (#7072) + + commit 59e634a8a841f58efeac873459bedf28928a83f9 + Author: Johannes Sixt + Date: Wed Jun 26 11:53:47 2024 +0200 + + [func.require] Add missing formatting of subscript index (#7071) + + commit 6d67d200863e430650047adb651324bc5663b6fc + Author: Jens Maurer + Date: Tue May 14 13:13:42 2024 +0200 + + [diff] Mark examples as such + + Fixes ISO/CS comment (C++23 proof) + + commit 21e022557462544e2e6d32411f71e42a378d2236 + Author: Jonathan Wakely + Date: Tue Jul 2 14:31:08 2024 +0100 + + [depr.c.macros] Fix "macro" singular when referring to two macros + + This should have been applied as part of LWG 4036. + + commit 8bb63636c37f8e67808de1e1ce1142a3028293fd + Author: Jonathan Wakely + Date: Wed Jul 3 20:53:40 2024 +0100 + + [istream.unformatted] add missing semi-colon to list item (#7117) + + commit 8227c196af96f157a539e5181f7a75ab3de3a096 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Jul 5 10:03:47 2024 +0200 + + [except.throw] Add comma (#7118) + + commit 07c20b75a867b66c858de716dfb639b0a9d1da2c + Author: Yihe Li + Date: Sat Jul 6 23:32:43 2024 +0800 + + [version.syn] Remove redundant for __cpp_lib_ranges_enumerate (#7120) + + commit 15b7ea6c95e471888cda2c334ba8ac30cabccf64 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sun Jul 7 10:23:09 2024 +0200 + + [basic.start.main] fix definite article (#7121) + + commit 61d85d3f9b78d792bd1bdb1d15202f9cdd931b31 + Author: Thomas Köppe + Date: Tue Jul 9 00:57:58 2024 +0100 + + [intro.compliance.general] Cite Annex B more normatively. + + commit 2048179f82bbe92dcccee3cc6bbdac4973c77606 + Author: Thomas Köppe + Date: Tue Jul 9 01:25:28 2024 +0100 + + [intro.compliance.general] Cite Annex D more normatively. + + commit 6b67a856495634df3a0bd0d8abee36eb0d3c8c6f + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Jul 9 08:29:50 2024 +0200 + + [temp.inst] Fix definite article + + commit 43c47b42fd1f7cd4d095299aca98666c06e45949 + Author: Thomas Köppe + Date: Tue Jul 9 01:44:08 2024 +0100 + + [uaxid] Clarify that requirements come "from UAX #31", and use "this document". + + commit 7c35cb057ef4885e091bf65c1103d64946e7c8d1 + Author: Thomas Köppe + Date: Tue Jul 9 14:47:10 2024 +0100 + + [std] Make bibliography reference link colour more citely + + commit bc2c80c23133a0581a847bd7fcfaca621ca86ffe + Author: Jens Maurer + Date: Mon May 13 20:17:21 2024 +0200 + + [dcl.init.list] Add commas and period for bulleted list + + Fixes ISO/CS comment (C++23 proof) + + commit 868db7356ad1490890391e8c82888de5c4d4aad4 + Author: Jens Maurer + Date: Mon May 13 20:18:20 2024 +0200 + + [facet.num.get.virtuals] Add missing punctuation + + Fixes ISO/CS comment (C++23 proof) + + commit 77ee6ed3b8865b2bb514cb8446488aa6fb032dda + Author: Jens Maurer + Date: Mon May 13 23:39:13 2024 +0200 + + [lex.literal] Properly format table headings + + Fixes ISO/CS comment (C++23 proof) + + commit cb9850377b88a4d7da12d05bcdf11948c384f699 + Author: Jens Maurer + Date: Mon May 13 23:47:55 2024 +0200 + + [basic.fundamental] Center second column of "integer width" table + + Fixes ISO/CS comment (C++23 proof) + + commit 2a2b8732e0d81dd9f5d3880b70bd451173e5f5fc + Author: Thomas Köppe + Date: Tue Jul 9 15:41:56 2024 +0100 + + [intro.defs] Minor rewording. Avoid sounding like a requirement. + + commit 4746925c7117015480542fd68ad5f595b78173d2 + Author: Jens Maurer + Date: Tue May 14 14:11:53 2024 +0200 + + [numeric.limits.members,bibliography] Remove LIA-1 abbreviation for ISO 10967 + + Fixes ISO/CS comment (C++23 proof) + + commit c18d51ddf436abf39065ea86497161383bba11c0 + Author: Jens Maurer + Date: Wed May 15 09:05:36 2024 +0200 + + [intro.memory] Move footnote about Unicode trademark to [lex.phases] + + Fixes ISO/CS comment (C++23 proof) + + commit 1f32f6aa8000f194f1b5c4daba94d271eea817fb + Author: Jens Maurer + Date: Wed May 15 16:28:34 2024 +0200 + + [diff,bibliography] Move details of old C++ standards to the bibliography + + Fixes ISO/CS comment (C++23 proof) + + commit d5410b4035e3108d48a63434abfff7e377c996d2 + Author: Jens Maurer + Date: Wed May 15 18:31:14 2024 +0200 + + [diff.cpp20,diff.cpp17] Add missing inclusion clause + + commit af4cf904c3d2df0675dbd456af2de2f1259e370c + Author: Jens Maurer + Date: Thu May 16 12:56:12 2024 +0200 + + [std] Rename 'In general' headings to 'General' for consistency + + Fixes ISO/CS comment (C++23 proof) + + commit 9d3011b4224bb63636f4a117967e8ba8110f5ba4 + Author: Jens Maurer + Date: Fri May 17 14:11:48 2024 +0200 + + [implimits] Rephrase introductory sentence for list of quantities + + Fixes ISO/CS comment (C++23 proof) + + commit 260d3a0d0cde1431dd4221115e1b37979ee07e7d + Author: Jens Maurer + Date: Thu May 16 12:30:44 2024 +0200 + + [class.copy.ctor] Remove reference to non-existing example + + Fixes ISO/CS comment (C++23 proof) + + commit 0bc3e030be28ff2191af8e9c9c202bff6e23c320 + Author: Jens Maurer + Date: Thu May 16 12:37:12 2024 +0200 + + [class.conv.general] Remove vague reference to unhelpful examples + + Fixes ISO/CS comment (C++23 proof) + + commit 861f07de24c5cfbd69840038d8589bc13b24b7e7 + Author: Jens Maurer + Date: Wed May 15 21:58:36 2024 +0200 + + [cpp.predefined,namespace.future,version.syn] Replace 'C++' with 'this document' + + Fixes ISO/CS comment (C++23 proof) + + commit a7a2cbd10ea752d49ca286e3fea3e7cbbb9b6e9d + Author: Jens Maurer + Date: Fri May 17 00:44:32 2024 +0200 + + [futures.state] Turn note into example + + Fixes ISO/CS comment (C++23 proof) + + commit 88c48bb78815576fb20db42b89f381c580d28b0e + Author: Jens Maurer + Date: Tue May 14 22:41:24 2024 +0200 + + [std] Remove colons in front of bulleted lists + + commit 9d7aa6108b84a09117463d0b13bc24cf61926897 + Author: Jens Maurer + Date: Tue May 14 22:47:38 2024 +0200 + + [iterators] Add colon after 'model ... only if' when complete sentences follow + + commit 79ac47f7053da4ef20c117e282377591d028e7a5 + Author: Jens Maurer + Date: Wed May 15 21:42:09 2024 +0200 + + [basic.fundamental,cstdarg.syn] Use full reference for ISO C sections + + Fixes ISO/CS comment (C++23) + + commit 2bbf136502811925250b09fd73909b78e0236091 + Author: Jens Maurer + Date: Thu May 16 12:51:32 2024 +0200 + + [execpol.general] Use 'this document', not 'this standard' + + Fixes ISO/CS comment (C++23 proof) + + commit e65393f3c87d323258e38c498b849dc57404a20b + Author: Jens Maurer + Date: Wed May 15 22:13:14 2024 +0200 + + [format.string.std] Add (R) symbol after Windows + + Fixes ISO/CS comment (C++23 proof) + + commit dafefea895de358b8edcb6780e3c7b71d209b458 + Author: Jens Maurer + Date: Tue May 14 19:12:57 2024 +0200 + + [rand.req] Replace 'that Table' with a precise reference + + Fixes ISO/CS comment (C++23 proof) + + commit 361e7769a245aad263574bbe83b9266d8da3b01b + Author: Jens Maurer + Date: Fri May 17 09:42:22 2024 +0200 + + [std] Replace 'this standard' with 'this document' + + Fixes ISO/CS comment (C++23 proof) + + commit e86031dd14e052956fc23ec4dbc1510b7438ba5b + Author: Jens Maurer + Date: Mon May 13 23:19:57 2024 +0200 + + [time.format,time.parse] Fix references to ISO week calendar + + Fixes ISO/CS comment (C++23 proof) + + commit 868b0b29ac16370ed8792442a0ab41be91c5d575 + Author: Jens Maurer + Date: Mon May 13 19:01:05 2024 +0200 + + [std] Avoid hanging paragraphs by introducing "General" subclauses + + Fixes ISO/CS comment (C++23 proof) + + commit f0580700cf0e8e920ceb3a078b6872a4c16fa225 + Author: Jens Maurer + Date: Wed May 15 21:49:31 2024 +0200 + + [std] Remove ISO from any mention of 'C' + + Fixes ISO/CS comment (C++23 proof) + + commit 69f184ea599635dac4cd9dc06a3303bed93b26f7 + Author: Jens Maurer + Date: Mon May 13 19:30:38 2024 +0200 + + [std] Remove mid-sentence 'subclause' introducer + + Fixes ISO/CS comment (C++23 proof) + + commit ecb071672b02a4b7bc829f87433d98785d9dd701 + Author: Jens Maurer + Date: Mon May 13 19:44:40 2024 +0200 + + [std] Remove incorrect or duplicative 'this subclause' introducers + + Fixes ISO/CS comment (C++23 proof) + + commit a249f9f37531fe79e768f19a45f1b1a70685c2c6 + Author: Thomas Köppe + Date: Tue Jul 9 22:48:20 2024 +0100 + + [classes] Turn ad-hoc examples into proper examples (#7125) + + commit eade3851e174ac014b478b8d4f097103d3b996ae + Author: Jens Maurer + Date: Thu May 16 12:44:01 2024 +0200 + + [lex.ccon,expr.prim.lambda.capture] Excise 'ISO' prefix + + Fixes ISO/CS comment (C++23 proof) + + commit 5383169856690cf05d946f058ed861119405d126 + Author: Jens Maurer + Date: Thu May 16 14:32:49 2024 +0200 + + [fs.class.path.general] Defuse cross-reference to POSIX + + Fixes ISO/CS comment (C++23 proof) + + commit 5731ab6a9122763bf6193d1382a05c7bebe82b38 + Author: Thomas Köppe + Date: Tue Jul 9 23:24:09 2024 +0100 + + [time.format] Remove mid-sentence 'subclause' introducer from external reference + + commit 856d175973d343d8e16d641221f47357672d9959 + Author: Jens Maurer + Date: Fri May 17 14:26:54 2024 +0200 + + [lib] Excise Note A, Note B, etc. designations + + Fixes ISO/CS comment (C++23 proof) + + commit 5508a007540d790a8f5cd30f863f4d329edf2694 + Author: Jens Maurer + Date: Thu May 16 15:07:27 2024 +0200 + + [macros,numerics] Add and use numbered 'formula' environment + + Fixes ISO/CS comment (C++23 proof) + + commit 2b0ff8d6bd285bbe8b27fdab47e268b115a3f930 + Author: Thomas Köppe + Date: Wed Jul 10 11:33:23 2024 +0100 + + [lex.string] Replace colon with full stop to end the sentence. + + On request of ISO/CS, for otherwise we should have made the next 'if' + lowercase, because: "Grammatically this is the same sentence, + as there is no full stop, so the 'if' should be lowercase." + + If a colon really doesn't end a sentence, then we should make it so + that the sentence really does end. + + commit 064fb0b34eb8cbb14f52dc966c833ef7c749c82c + Author: Jens Maurer + Date: Tue May 14 08:23:07 2024 +0200 + + [macros] Prefer page break above 'note' or 'example' introducers + + Fixes ISO/CS comment (C++23 proof) + + commit 13b08d0f58dfea7ae2e19b1d931094d4523a52d2 + Author: Thomas Köppe + Date: Thu Jul 11 01:41:29 2024 +0100 + + [layout, styles] New ISO header and footer layout. + + The footer now takes up two lines, one for the copyright and one for + the page number. + + commit 7f6069c794abb56e51affdc2923e3d33b3a547a8 + Author: Thomas Köppe + Date: Thu Jul 11 12:27:28 2024 +0100 + + [cover-reg] Update regular cover + + commit f41a619cf852ae638bfe4792ec78ac1f214a7d23 + Author: Thomas Köppe + Date: Fri Jul 12 01:28:38 2024 +0100 + + [impldefindex] Reinstate full page mark + + As of 13b08d0f58dfea7ae2e19b1d931094d4523a52d2 we have space for it. + + commit b2870b5c87765946f5c4a644da508adcc483045e + Author: Thomas Köppe + Date: Fri Jul 12 01:30:06 2024 +0100 + + [macros, std] Create macros for ISO/IEC 60559 and ISO/IEC/IEEE 9945. + + As a side effect, this corrects the title of ISO/IEC 60559(:2020), + whose previous version was ISO/IEC/IEEE 60559:2011. diff --git a/papers/n4989.html b/papers/n4989.html new file mode 100644 index 0000000000..00eecf259e --- /dev/null +++ b/papers/n4989.html @@ -0,0 +1,569 @@ + + + + + +N4989 Editors’ Report: Programming Languages — C++ + + +

N4989 Editors’ Report:
Programming Languages — C++

+ +

Date: 2024-08-05

+ +

Thomas Köppe (editor, Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor, Bright Side Computing, LLC)
+Richard Smith (co-editor, Google Inc)

+ +

Email: cxxeditor@gmail.com

+ +

Acknowledgements

+ +

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

+ +

New papers

+ +
    +
  • N4988 is the +current working draft for C++26. It replaces +N4986.
  • +
  • N4989 is this Editors' Report.
  • +
+ +

Draft approval

+ +

The previous draft +N4986 +was not approved at any WG21 meeting. For approval of this draft, N4988, +please consult the previous Editors' report +N4987 +as well as this one.

+ +

Motions incorporated into working draft

+ +

Notes on motions

+ +

All passed motions from CWG and LWG motions 1 through 9 were applied in the previous draft +N4986. +LWG motions 10, 11, and 12 had not yet been applied due to a lack of time, +and are included in this draft.

+ +

The full list of approved motions is included here for ease of reference.

+ +

Core working group polls

+ +

Already applied in previous draft.

+ +

CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues except 2819, 2858, and 2876 in +P3345R0 +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper.

+ +

CWG Poll 2. Apply the proposed resolution of issues 2819, 2858, and 2876 in +P3345R0 +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper.

+ +

CWG Poll 3. Apply the changes in +P2747R2 +(constexpr placement new) to the C++ Working Paper.

+ +

CWG Poll 5. Apply the changes in +P3144R2 +(Deleting a Pointer to an Incomplete Type Should be Ill-formed) to the C++ Working Paper.

+ +

CWG Poll 6. Apply the changes in +P2963R3 +(Ordering of constraints involving fold expressions) to the C++ Working Paper.

+ +

CWG Poll 7. Apply the changes in +P0963R3 +(Structured binding declaration as a condition) to the C++ Working Paper.

+ +

CWG Poll 4 did not have consensus.

+ +

Library working group polls

+ +

Already applied in previous draft.

+ +

LWG Poll 1. Apply the changes for all Ready and Tentatively Ready issues in +P3341R0 +(C++ Standard Library Ready Issues to be moved in St. Louis, Jun. 2024) to the C++ working paper.

+ +

LWG Poll 2. Apply the changes in +P2997R1 +(Removing the common reference requirement from the indirectly invocable concepts) to the C++ working paper.

+ +

LWG Poll 3. Apply the changes in +P2389R2 +(dextents Index Type Parameter) to the C++ working paper.

+ +

LWG Poll 4. Apply the changes in +P3168R2 +(Give std::optional Range Support) to the C++ working paper.

+ +

LWG Poll 5. Apply the changes in +P3217R0 +(Adjoints to "Enabling list-initialization for algorithms": find_last) to the C++ working paper.

+ +

LWG Poll 6. Apply the changes in +P2985R0 +(A type trait for detecting virtual base classes) to the C++ working paper.

+ +

LWG Poll 7. Apply the changes in +P0843R14 +(inplace_vector) to the C++ working paper.

+ +

LWG Poll 8. Accept as a Defect Report and apply the changes in +P3235R3 +(std::print more types faster with less memory) to the C++ working paper.

+ +

LWG Poll 9. Apply the changes in +P2968R2 +(Make std::ignore a first-class object) to the C++ working paper.

+ +

Newly applied in this draft:

+ +

LWG Poll 10. Apply the changes in +P2075R6 +(Philox as an extension of the C++ RNG engines) to the C++ working paper.

+ +

LWG Poll 11. Apply the changes in +P2422R1 +(Remove nodiscard annotations from the standard library specification) to the C++ working paper.

+ +

LWG Poll 12. Apply the changes in +P2300R10 +(std::execution) to the C++ working paper.

+ +

Editorial changes

+ +

Major editorial changes

+ +

There were no major editorial changes.

+ +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N4986 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 a52859fad0d3bc56ec941fc287d5cebc0fd080dc
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Jul 12 14:35:07 2024 +0100
+
+    [diff.cpp23.dcl.dcl] Fix capitalisation of heading
+
+commit 811e9bb15fe6b8fe0a6e5584525b7839e329126b
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 23 00:19:37 2024 +0100
+
+    [intro.refs] Move footnote
+
+    As requested by ISO/CS.
+
+commit dd306a57cdcce4596fb9d5ce917075eee8e60f4b
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 23 00:22:31 2024 +0100
+
+    [intro.races] Rephrase note to avoid awkward "can not".
+
+    Suggested by ISO/CS.
+
+commit 3dc8333128753e8eb4c39f353aa272a63221e6d5
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 23 00:28:48 2024 +0100
+
+    [library.c] Clarify that Annex F comes from ISO/IEC 9899:2018
+
+commit b303620f529bfe517fb0c79d3e7f644c54a1e6cb
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Jul 23 00:20:42 2024 +0100
+
+    [rand.dist] Remove textual elements from forumla.
+
+    Those were left over from when we converted the text-integrated
+    formula to self-contained, numbered ones.
+
+commit 7228e06a7973282cf1034a9cdb095dd863aef377
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Jul 17 00:48:45 2024 +0100
+
+    [tab:headers.cpp.fs] Use a more appropriate subclause for inplace_vector
+
+commit 3f5771916e846d16330a87df15d35e797ea66437
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Jul 23 17:48:36 2024 -0400
+
+    [depr.c.macros] Cross-reference the C headers for deprecated macros
+
+commit be25cad169c62518e934cd3269e966091b20a4c4
+Author: A. Jiang <de34@live.cn>
+Date:   Mon Jul 22 17:25:04 2024 +0800
+
+    [inplace.vector.syn] Default template argument for `erase`
+
+    The default template argument is already in [inplace.vector.erasure].
+
+commit e0fe4a30614303116dc91357ab1bb483dc98b2ca
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Jul 22 00:24:26 2024 +0800
+
+    [inplace.vector.modifiers] Fix typo
+
+commit 420cff6a620498b6e6b0a4a7f0757bfa8dfb2a1c
+Author: Hewill Kang <hewillk@gmail.com>
+Date:   Sun Jul 28 00:05:29 2024 +0800
+
+    [func.search.bm] Remove superfluous the (#7160)
+
+commit cf27216f6aeba4a7e1debed304303fc2e69b2d65
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Jul 22 13:11:05 2024 +0800
+
+    [inplace.vector.erasure] Added missing return statement
+
+commit dc8b2d4d198a307b749832044e2819de1378ace7
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Jul 23 22:28:38 2024 -0400
+
+    [locale.ctype.general] Better cross-ref standard headers
+
+commit f181708d17038c0ebe42aff9d61e79222e5a06b0
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Jul 19 20:33:06 2024 +0100
+
+    [basic.indet] Fix "errorneous" typo
+
+commit 1a15d3a3d84549687eb65a870952441c869f31a9
+Author: A. Jiang <de34@live.cn>
+Date:   Sun Jul 28 07:56:03 2024 +0800
+
+    Make cross-reference more precise. (#7144)
+
+    Co-authored-by: Eelis van der Weegen <eelis@eelis.net>
+
+commit 930502061ea47c184c3b25ed623801dfa5284167
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sun Jul 28 01:57:52 2024 +0200
+
+    [temp.constr.normal] Remove duplicate "the" (#7135)
+
+commit 11e13d5d858f06ec163ece2881af642a23fe5b96
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sun Jul 28 01:58:09 2024 +0200
+
+    [diff.cpp23.expr] Remove duplicate "that" (#7134)
+
+commit 8ead4680a67cacffe82e2fd74e64df76120cb1a9
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Wed Jul 10 20:28:34 2024 +0800
+
+    [variant.visit] Add constexpr to as-variant
+
+commit 8d8861cdc944b784db14be27ce2541071288dcc5
+Author: A. Jiang <de34@live.cn>
+Date:   Mon May 13 00:33:24 2024 +0800
+
+    [print.syn] Show `locking` functions in the synopsis of `<print>`
+
+commit 5c3858e09e73c49748901aceb33acc7cd86bd7de
+Author: Eelis <github.com@contacts.eelis.net>
+Date:   Sun Jul 28 13:35:39 2024 +0200
+
+    [exec.snd.general] Add missing period (#7172)
+
+commit 3e87f29c42ad38e224ac6e7e75dc08220b440189
+Author: Eelis <github.com@contacts.eelis.net>
+Date:   Sun Jul 28 13:37:06 2024 +0200
+
+    [out.ptr.t] Fix bullet placement for item that starts with codeblock (#7173)
+
+commit 81d85dfbee01b8fdf993fac4efeb40fb00b18144
+Author: Eelis <github.com@contacts.eelis.net>
+Date:   Sun Jul 28 13:39:12 2024 +0200
+
+    [range.concat.iterator] Remove stray hyphen (#7171)
+
+commit 500b8f49f28b51c576eb671ee067efcc1bc002a9
+Author: A. Jiang <de34@live.cn>
+Date:   Sun Jul 28 22:22:54 2024 +0800
+
+    [print.syn] Update `locking` to `buffered` (#7168)
+
+    The function names were changed by P3235R3.
+
+commit 9b3d01e82b03e26cf9e1fa06a582ec931ca00052
+Author: Eelis <github.com@contacts.eelis.net>
+Date:   Sun Jul 28 21:16:58 2024 +0200
+
+    [execution.syn] Fix read_env name (#7169)
+
+commit 5bac031ccb4f7ce511c6e95b63b39eee2eb14c87
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Jul 27 00:48:42 2024 +0100
+
+    [stoptoken.general, stopsource.general] Remove DMI from stop-state member
+
+    For stoptoken::stop-state, the default-initialized value is already
+    correct, and no further "{}" initializer is needed.
+
+    For stopsource::stop-state, the DMI "{}" is never used, since the
+    constructor is explicitly specified and not defaulted.
+
+commit 917c271c926214e286f560c4a3f2aadc59dadcb7
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Jul 27 00:12:22 2024 +0100
+
+    [exec.snd.general] Remove disconnected and obsolete paragraph.
+
+commit 609068d41d699b85b0677fbb206235a4bc30fd77
+Author: Eisenwave <me@eisenwave.net>
+Date:   Sat Jun 8 16:13:36 2024 +0200
+
+    [array.cons] Fix various wording issues
+
+commit f8468b9606aa4db0a55f1ecde046025876c5de23
+Author: Eisenwave <me@eisenwave.net>
+Date:   Sun Aug 6 21:52:00 2023 +0200
+
+    [expr.cond] itemize p4
+
+commit d9bff4abf4e4de12ef816d3e9df4ed5c6733da64
+Author: Hewill Kang <hewillk@gmail.com>
+Date:   Mon Jul 29 23:31:19 2024 +0800
+
+    [coro.generator] Rename the generator's template parameter "V" to "Val" (#7129)
+
+commit aa4a13e9ea6e81e7d2ef5205de9e1f765a27bbbe
+Author: Eisenwave <me@eisenwave.net>
+Date:   Sat Aug 19 13:33:10 2023 +0200
+
+    [basic.fundamental] itemize uses of void expressions
+
+commit 0711baa8bf611656aae770a6bc23b7ee96ed5811
+Author: Eisenwave <me@eisenwave.net>
+Date:   Sat Aug 19 13:47:04 2023 +0200
+
+    [basic.fundamental] remove redundant void conversion wording
+
+commit 5342083f2c84f6592c455562d8a6b464d39d86ba
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Mon Jun 17 10:55:22 2024 +0700
+
+    [cpp.pre] define, index, and consistently use the term 'logical source line'
+
+commit 56079f18c4751d4dd15fbdf7d50179d2044345f3
+Author: Casey Carter <Casey@Carter.net>
+Date:   Fri Jan 12 10:35:39 2024 -0800
+
+    [structure.specifications] clarify description of Results element
+
+    The text "... the expression is an lvalue if the type is an lvalue reference type, an xvalue if the type is an rvalue reference type, and a prvalue otherwise" clearly indicates that a Result element describes the type and value category of an expression, yet we summarize it as only "a description of the type of the expression".
+
+commit 407c552023c069afc2438cd462049a323c971bb1
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Tue Jul 16 19:41:36 2024 -0400
+
+    [deque, forward.list, list, vector] Fix instances of "FooInsertable into *this"
+
+    Fixes #7133
+
+commit 4bf5bd233461b49924ea330b95698fdc43cf3636
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Apr 25 00:46:41 2024 +0800
+
+    [alg.replace] Fix misapplication of P2248R8 to `std::replace_copy`
+
+    Removes wrongly added default template arguments that are not present in that paper.
+
+commit d0615b3d8b991fd0cd58fbd6b75da727423cff4e
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Jul 23 22:20:27 2024 -0400
+
+    [containers] Consistently xref header synopses from General clauses
+
+commit 35904b92e4bbabd0303f8fb7cbbe3a6142639876
+Author: A. Jiang <de34@live.cn>
+Date:   Sat Apr 27 00:46:29 2024 +0800
+
+    [expr.call] Say implicit object parameter instead of `this`
+
+    And correct the initialization of the implicit object parameter.
+
+commit 7f76c21f933b167d71a1ff12584911e82477454d
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Jul 29 18:48:49 2024 +0100
+
+    [alg.search] Replace "the following corresponding conditions"
+
+    It's not clear which conditions correspond to each overload.
+
+commit 69ddb6ec0b50c92390391ec54b97c92ef2179869
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Mon Jul 29 21:54:11 2024 +0200
+
+    [exec.stopped.opt] Fix indefinite article (#7186)
+
+commit 4800c7b83d2fbde2c63c6811716bf62df047f5ae
+Author: Hewill Kang <hewillk@gmail.com>
+Date:   Tue Jul 30 18:02:17 2024 +0800
+
+    [range.join.with.iterator] Fix typo (#7131)
+
+commit 3dba07b8277a59792430cd166192ed41e428c6f7
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Jul 30 12:03:20 2024 +0200
+
+    [exec.util.cmplsig.trans] Fix English grammar (#7188)
+
+commit f640daed4a6304ef4e2c289c6d42e754d06cd4ee
+Author: Anoop Rana <93918384+ranaanoop@users.noreply.github.com>
+Date:   Thu Jul 25 19:57:36 2024 +0530
+
+    [basic.scope.scope] Replaced the term top-level reference with just reference
+
+    [basic.scope.scope] Replaced the term top-level reference with just reference in light of [this issue](https://github.com/cplusplus/CWG/issues/569)
+
+commit 54fb7eb6ada6e7a4d47c9a310675d5cf55bbd5c7
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Jul 30 16:22:02 2024 -0400
+
+    [lex.pptoken] Consistent use of preprocessing vs processing
+
+    There are three cases here all doing the same thing.  Two
+    refer to preprocessing a directive, while the first refers
+    to processing without the pre.
+
+ + diff --git a/papers/n4989.md b/papers/n4989.md new file mode 100644 index 0000000000..6a639a8806 --- /dev/null +++ b/papers/n4989.md @@ -0,0 +1,428 @@ +# N4989 Editors' Report -- Programming Languages -- C++ + +Date: 2024-08-05 + +Thomas Köppe (editor, Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor, Bright Side Computing, LLC) +Richard Smith (co-editor, Google Inc) + +Email: `cxxeditor@gmail.com` + +## Acknowledgements + +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 + + * [N4988](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf) is the + current working draft for C++26. It replaces + [N4986](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4986.pdf). + * N4989 is this Editors' Report. + +## Draft approval + +The previous draft +[N4986](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4986.pdf) +was not approved at any WG21 meeting. For approval of this draft, N4988, +please consult the previous Editors' report +[N4987](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4987.html) +as well as this one. + +## Motions incorporated into working draft + +### Notes on motions + +All passed motions from CWG and LWG motions 1 through 9 were applied in the previous draft +[N4986](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4986.pdf). +LWG motions 10, 11, and 12 had not yet been applied due to a lack of time, +and are included in this draft. + +The full list of approved motions is included here for ease of reference. + +### Core working group polls + +**Already applied in previous draft.** + +CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues except 2819, 2858, and 2876 in +[P3345R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3345r0.html) +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper. + +CWG Poll 2. Apply the proposed resolution of issues 2819, 2858, and 2876 in +[P3345R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3345r0.html) +(Core Language Working Group "ready" Issues for the June, 2024 meeting) to the C++ Working Paper. + +CWG Poll 3. Apply the changes in +[P2747R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html) +(`constexpr` placement new) to the C++ Working Paper. + +CWG Poll 5. Apply the changes in +[P3144R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3144r2.pdf) +(Deleting a Pointer to an Incomplete Type Should be Ill-formed) to the C++ Working Paper. + +CWG Poll 6. Apply the changes in +[P2963R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2963r3.pdf) +(Ordering of constraints involving fold expressions) to the C++ Working Paper. + +CWG Poll 7. Apply the changes in +[P0963R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0963r3.html) +(Structured binding declaration as a condition) to the C++ Working Paper. + +CWG Poll 4 did not have consensus. + +### Library working group polls + +**Already applied in previous draft.** + +LWG Poll 1. Apply the changes for all Ready and Tentatively Ready issues in +[P3341R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3341r0.html) +(C++ Standard Library Ready Issues to be moved in St. Louis, Jun. 2024) to the C++ working paper. + +LWG Poll 2. Apply the changes in +[P2997R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2997r1.html) +(Removing the common reference requirement from the indirectly invocable concepts) to the C++ working paper. + +LWG Poll 3. Apply the changes in +[P2389R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2389r2.html) +(`dextents` Index Type Parameter) to the C++ working paper. + +LWG Poll 4. Apply the changes in +[P3168R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3168r2.html) +(Give `std::optional` Range Support) to the C++ working paper. + +LWG Poll 5. Apply the changes in +[P3217R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3217r0.html) +(Adjoints to "Enabling list-initialization for algorithms": `find_last`) to the C++ working paper. + +LWG Poll 6. Apply the changes in +[P2985R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2985r0.html) +(A type trait for detecting virtual base classes) to the C++ working paper. + +LWG Poll 7. Apply the changes in +[P0843R14](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0843r14.html) +(`inplace_vector`) to the C++ working paper. + +LWG Poll 8. Accept as a Defect Report and apply the changes in +[P3235R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3235r3.html) +(std::print more types faster with less memory) to the C++ working paper. + +LWG Poll 9. Apply the changes in +[P2968R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2968r2.html) +(Make std::ignore a first-class object) to the C++ working paper. + +**Newly applied in this draft:** + +LWG Poll 10. Apply the changes in +[P2075R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2075r6.pdf) +(Philox as an extension of the C++ RNG engines) to the C++ working paper. + +LWG Poll 11. Apply the changes in +[P2422R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2422r1.html) +(Remove nodiscard annotations from the standard library specification) to the C++ working paper. + +LWG Poll 12. Apply the changes in +[P2300R10](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2300r10.html) +(std::execution) to the C++ working paper. + +## Editorial changes + +### Major editorial changes + +There were no major editorial changes. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N4986 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/n4986...n4988). + + commit a52859fad0d3bc56ec941fc287d5cebc0fd080dc + Author: Thomas Köppe + Date: Fri Jul 12 14:35:07 2024 +0100 + + [diff.cpp23.dcl.dcl] Fix capitalisation of heading + + commit 811e9bb15fe6b8fe0a6e5584525b7839e329126b + Author: Thomas Köppe + Date: Tue Jul 23 00:19:37 2024 +0100 + + [intro.refs] Move footnote + + As requested by ISO/CS. + + commit dd306a57cdcce4596fb9d5ce917075eee8e60f4b + Author: Thomas Köppe + Date: Tue Jul 23 00:22:31 2024 +0100 + + [intro.races] Rephrase note to avoid awkward "can not". + + Suggested by ISO/CS. + + commit 3dc8333128753e8eb4c39f353aa272a63221e6d5 + Author: Thomas Köppe + Date: Tue Jul 23 00:28:48 2024 +0100 + + [library.c] Clarify that Annex F comes from ISO/IEC 9899:2018 + + commit b303620f529bfe517fb0c79d3e7f644c54a1e6cb + Author: Thomas Köppe + Date: Tue Jul 23 00:20:42 2024 +0100 + + [rand.dist] Remove textual elements from forumla. + + Those were left over from when we converted the text-integrated + formula to self-contained, numbered ones. + + commit 7228e06a7973282cf1034a9cdb095dd863aef377 + Author: Thomas Köppe + Date: Wed Jul 17 00:48:45 2024 +0100 + + [tab:headers.cpp.fs] Use a more appropriate subclause for inplace_vector + + commit 3f5771916e846d16330a87df15d35e797ea66437 + Author: Alisdair Meredith + Date: Tue Jul 23 17:48:36 2024 -0400 + + [depr.c.macros] Cross-reference the C headers for deprecated macros + + commit be25cad169c62518e934cd3269e966091b20a4c4 + Author: A. Jiang + Date: Mon Jul 22 17:25:04 2024 +0800 + + [inplace.vector.syn] Default template argument for `erase` + + The default template argument is already in [inplace.vector.erasure]. + + commit e0fe4a30614303116dc91357ab1bb483dc98b2ca + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Jul 22 00:24:26 2024 +0800 + + [inplace.vector.modifiers] Fix typo + + commit 420cff6a620498b6e6b0a4a7f0757bfa8dfb2a1c + Author: Hewill Kang + Date: Sun Jul 28 00:05:29 2024 +0800 + + [func.search.bm] Remove superfluous the (#7160) + + commit cf27216f6aeba4a7e1debed304303fc2e69b2d65 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Jul 22 13:11:05 2024 +0800 + + [inplace.vector.erasure] Added missing return statement + + commit dc8b2d4d198a307b749832044e2819de1378ace7 + Author: Alisdair Meredith + Date: Tue Jul 23 22:28:38 2024 -0400 + + [locale.ctype.general] Better cross-ref standard headers + + commit f181708d17038c0ebe42aff9d61e79222e5a06b0 + Author: Jonathan Wakely + Date: Fri Jul 19 20:33:06 2024 +0100 + + [basic.indet] Fix "errorneous" typo + + commit 1a15d3a3d84549687eb65a870952441c869f31a9 + Author: A. Jiang + Date: Sun Jul 28 07:56:03 2024 +0800 + + Make cross-reference more precise. (#7144) + + Co-authored-by: Eelis van der Weegen + + commit 930502061ea47c184c3b25ed623801dfa5284167 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sun Jul 28 01:57:52 2024 +0200 + + [temp.constr.normal] Remove duplicate "the" (#7135) + + commit 11e13d5d858f06ec163ece2881af642a23fe5b96 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sun Jul 28 01:58:09 2024 +0200 + + [diff.cpp23.expr] Remove duplicate "that" (#7134) + + commit 8ead4680a67cacffe82e2fd74e64df76120cb1a9 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Wed Jul 10 20:28:34 2024 +0800 + + [variant.visit] Add constexpr to as-variant + + commit 8d8861cdc944b784db14be27ce2541071288dcc5 + Author: A. Jiang + Date: Mon May 13 00:33:24 2024 +0800 + + [print.syn] Show `locking` functions in the synopsis of `` + + commit 5c3858e09e73c49748901aceb33acc7cd86bd7de + Author: Eelis + Date: Sun Jul 28 13:35:39 2024 +0200 + + [exec.snd.general] Add missing period (#7172) + + commit 3e87f29c42ad38e224ac6e7e75dc08220b440189 + Author: Eelis + Date: Sun Jul 28 13:37:06 2024 +0200 + + [out.ptr.t] Fix bullet placement for item that starts with codeblock (#7173) + + commit 81d85dfbee01b8fdf993fac4efeb40fb00b18144 + Author: Eelis + Date: Sun Jul 28 13:39:12 2024 +0200 + + [range.concat.iterator] Remove stray hyphen (#7171) + + commit 500b8f49f28b51c576eb671ee067efcc1bc002a9 + Author: A. Jiang + Date: Sun Jul 28 22:22:54 2024 +0800 + + [print.syn] Update `locking` to `buffered` (#7168) + + The function names were changed by P3235R3. + + commit 9b3d01e82b03e26cf9e1fa06a582ec931ca00052 + Author: Eelis + Date: Sun Jul 28 21:16:58 2024 +0200 + + [execution.syn] Fix read_env name (#7169) + + commit 5bac031ccb4f7ce511c6e95b63b39eee2eb14c87 + Author: Thomas Köppe + Date: Sat Jul 27 00:48:42 2024 +0100 + + [stoptoken.general, stopsource.general] Remove DMI from stop-state member + + For stoptoken::stop-state, the default-initialized value is already + correct, and no further "{}" initializer is needed. + + For stopsource::stop-state, the DMI "{}" is never used, since the + constructor is explicitly specified and not defaulted. + + commit 917c271c926214e286f560c4a3f2aadc59dadcb7 + Author: Thomas Köppe + Date: Sat Jul 27 00:12:22 2024 +0100 + + [exec.snd.general] Remove disconnected and obsolete paragraph. + + commit 609068d41d699b85b0677fbb206235a4bc30fd77 + Author: Eisenwave + Date: Sat Jun 8 16:13:36 2024 +0200 + + [array.cons] Fix various wording issues + + commit f8468b9606aa4db0a55f1ecde046025876c5de23 + Author: Eisenwave + Date: Sun Aug 6 21:52:00 2023 +0200 + + [expr.cond] itemize p4 + + commit d9bff4abf4e4de12ef816d3e9df4ed5c6733da64 + Author: Hewill Kang + Date: Mon Jul 29 23:31:19 2024 +0800 + + [coro.generator] Rename the generator's template parameter "V" to "Val" (#7129) + + commit aa4a13e9ea6e81e7d2ef5205de9e1f765a27bbbe + Author: Eisenwave + Date: Sat Aug 19 13:33:10 2023 +0200 + + [basic.fundamental] itemize uses of void expressions + + commit 0711baa8bf611656aae770a6bc23b7ee96ed5811 + Author: Eisenwave + Date: Sat Aug 19 13:47:04 2023 +0200 + + [basic.fundamental] remove redundant void conversion wording + + commit 5342083f2c84f6592c455562d8a6b464d39d86ba + Author: Alisdair Meredith + Date: Mon Jun 17 10:55:22 2024 +0700 + + [cpp.pre] define, index, and consistently use the term 'logical source line' + + commit 56079f18c4751d4dd15fbdf7d50179d2044345f3 + Author: Casey Carter + Date: Fri Jan 12 10:35:39 2024 -0800 + + [structure.specifications] clarify description of Results element + + The text "... the expression is an lvalue if the type is an lvalue reference type, an xvalue if the type is an rvalue reference type, and a prvalue otherwise" clearly indicates that a Result element describes the type and value category of an expression, yet we summarize it as only "a description of the type of the expression". + + commit 407c552023c069afc2438cd462049a323c971bb1 + Author: Arthur O'Dwyer + Date: Tue Jul 16 19:41:36 2024 -0400 + + [deque, forward.list, list, vector] Fix instances of "FooInsertable into *this" + + Fixes #7133 + + commit 4bf5bd233461b49924ea330b95698fdc43cf3636 + Author: A. Jiang + Date: Thu Apr 25 00:46:41 2024 +0800 + + [alg.replace] Fix misapplication of P2248R8 to `std::replace_copy` + + Removes wrongly added default template arguments that are not present in that paper. + + commit d0615b3d8b991fd0cd58fbd6b75da727423cff4e + Author: Alisdair Meredith + Date: Tue Jul 23 22:20:27 2024 -0400 + + [containers] Consistently xref header synopses from General clauses + + commit 35904b92e4bbabd0303f8fb7cbbe3a6142639876 + Author: A. Jiang + Date: Sat Apr 27 00:46:29 2024 +0800 + + [expr.call] Say implicit object parameter instead of `this` + + And correct the initialization of the implicit object parameter. + + commit 7f76c21f933b167d71a1ff12584911e82477454d + Author: Jonathan Wakely + Date: Mon Jul 29 18:48:49 2024 +0100 + + [alg.search] Replace "the following corresponding conditions" + + It's not clear which conditions correspond to each overload. + + commit 69ddb6ec0b50c92390391ec54b97c92ef2179869 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Mon Jul 29 21:54:11 2024 +0200 + + [exec.stopped.opt] Fix indefinite article (#7186) + + commit 4800c7b83d2fbde2c63c6811716bf62df047f5ae + Author: Hewill Kang + Date: Tue Jul 30 18:02:17 2024 +0800 + + [range.join.with.iterator] Fix typo (#7131) + + commit 3dba07b8277a59792430cd166192ed41e428c6f7 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Jul 30 12:03:20 2024 +0200 + + [exec.util.cmplsig.trans] Fix English grammar (#7188) + + commit f640daed4a6304ef4e2c289c6d42e754d06cd4ee + Author: Anoop Rana <93918384+ranaanoop@users.noreply.github.com> + Date: Thu Jul 25 19:57:36 2024 +0530 + + [basic.scope.scope] Replaced the term top-level reference with just reference + + [basic.scope.scope] Replaced the term top-level reference with just reference in light of [this issue](https://github.com/cplusplus/CWG/issues/569) + + commit 54fb7eb6ada6e7a4d47c9a310675d5cf55bbd5c7 + Author: Alisdair Meredith + Date: Tue Jul 30 16:22:02 2024 -0400 + + [lex.pptoken] Consistent use of preprocessing vs processing + + There are three cases here all doing the same thing. Two + refer to preprocessing a directive, while the first refers + to processing without the pre. diff --git a/papers/n4994.html b/papers/n4994.html new file mode 100644 index 0000000000..1778a35243 --- /dev/null +++ b/papers/n4994.html @@ -0,0 +1,737 @@ + + + + + +N4994 Editors’ Report: Programming Languages — C++ + + +

N4994 Editors’ Report:
Programming Languages — C++

+ +

Date: 2024-10-16

+ +

Thomas Köppe (editor, Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor, Bright Side Computing, LLC)
+Richard Smith (co-editor, Google Inc)

+ +

Email: cxxeditor@gmail.com

+ +

Acknowledgements

+ +

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

+ +

New papers

+ +
    +
  • N4993 is the +current working draft for C++26. It replaces +N4988.
  • +
  • N4994 is this Editors' Report.
  • +
+ +

Draft approval

+ +

The previous drafts +N4986 +and +N4988 +were not approved at any WG21 meeting. For approval of this draft, N4993, +please consult the previous Editors' reports +N4987 +and +N4989 +as well as this one.

+ +

No motions

+ +

There have been no new, approved WG21 motions. +This revision contains only editorial changes.

+ +

A few of the editorial changes fix mistakes in our LaTeX sources that were +reported to us by the ISO secretariat during the ongoing publication of C++23.

+ +

Editorial changes

+ +

Major editorial changes

+ +

For this revision, we have reorganised several clauses and subclauses. +As a reminder: the editorial team aims to perform only one major reorganisation +that changes top-level clause numbers per C++ revision, and this is it for C++26.

+ +

The changes create a new clause "Text processing library [text]" that collects +formatting, conversions, locales, regular expressions, and text-related C library +facilities. Clauses are rearranged as:

+ +
    +
  • Algorithms library [algorithms]
  • +
  • Strings library [strings]
  • +
  • Text processing library [text]
  • +
  • Numerics library [numerics]
  • +
  • Time library [time]
  • +
  • Input/output library [input.output]
  • +
+ +

The new [text] clause obtains the following contents:

+ +
    +
  • Primitive numeric conversions [charconv], from [utilities]
  • +
  • Formatting [format], from [utilities]
  • +
  • Text encodings identification [text.encoding], extracted from [localization]
  • +
  • Localization library [localization]
  • +
  • Regular expressions library [re]
  • +
  • C library facilities [cctype.syn], [cwctype.syn], [cwchar.syn], [cuchar.syn], and [c.mb.wcs]
  • +
+ +

Additionally, the following subclauses are moved:

+ +
    +
  • Debugging [debugging] from [utilities] to the end of [diagnostics]
  • +
  • Execution policies [execpol] from [utilities] to the end of [algorithms.parallel]
  • +
  • Class type_index [type.index] from [utilities] to [support.rtti]
  • +
+ +

This removes a number of unrelated clauses from the large [utilities] clause.

+ +

Finally, we spread the synopses in [containers] out to appear right in front +of the classes they define.

+ +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N4988 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 15a43d522467d389bd9340081d65dbf17d44d255
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 5 12:21:56 2024 +0100
+
+    [temp.over.link] Reword to clarify that declarations correspond (#5999)
+
+commit 3c0f4cf0a03892157ebf3a472d3e9450a41f038e
+Author: Lewis Baker <lewissbaker@users.noreply.github.com>
+Date:   Sun Aug 4 09:26:26 2024 +0930
+
+    [snd.expos] Fix typo in definition of SCHED-ENV exposition-only helper
+
+    Change `o1` -> `o2` to reference the expression declared as part of the definition of `SCHED-ENV`.
+
+commit 5056b86597f5ba9278601db46a415f2d76e1bc8f
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Aug 2 17:38:05 2024 +0200
+
+    [temp.constr.order] Reflect fold expanded constraints in footnotes
+
+commit c92bc384b118412322f9893832508bf17f46f644
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Aug 1 12:35:50 2024 +0200
+
+    [dcl.fct] Fix obsolete phrasing when defining 'function type'
+
+commit fabbff2d812e0a99bd1162460812ec2f5399636e
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Thu Aug 8 17:15:39 2024 -0400
+
+    [sequences] Consistent comma in "If X, there are no effects" (#7139)
+
+commit 04c5a0c509dbf8f9f81223d1de5bb917cd3074c5
+Author: Hana Dusíková <hanicka@hanicka.net>
+Date:   Tue Aug 20 12:21:43 2024 +0200
+
+    [meta.const.eval] Fix function declaration in example (#7234)
+
+commit ab4c0663dc72f09fb8ef6c366352c9d1a68e8fa9
+Author: Vlad Serebrennikov <serebrennikov.vladislav@gmail.com>
+Date:   Fri Aug 23 22:06:05 2024 +0400
+
+    [expr.prim.lambda.capture] Incorporate ellipsis into "captured by copy" definition
+
+commit 6ea6df4c96653d6696bb0133253ea0159b0f278f
+Author: Vlad Serebrennikov <serebrennikov.vladislav@gmail.com>
+Date:   Sat Aug 24 23:24:01 2024 +0400
+
+    [dcl.type.elab] Remove redundant full stop (#7242)
+
+commit 24ceda755967b022e8e089d4f0cdcf4bc99a4adb
+Author: Hewill Kang <hewillk@gmail.com>
+Date:   Mon Aug 26 18:29:28 2024 +0800
+
+    [exec.snd.apply,exec.schedule.from] Properly mark "see below" (#7210)
+
+commit 447b6291061d50a582f72dd42d9d6265857ded5c
+Author: Joachim Wuttke <j.wuttke@fz-juelich.de>
+Date:   Mon Aug 26 22:30:39 2024 +0200
+
+    [numerics] Correct typo Bessell -> Bessel (#7244)
+
+commit db0ca108a9b44ef8f06338ecf68f1e4653be4267
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Thu Aug 29 06:13:18 2024 -0400
+
+    [inplace.vector] Fix some spelling/grammar issues (#7243)
+
+commit 21e477fb6dbfa7813eb2263bfa31c748bdce589b
+Author: Casey Carter <Casey@Carter.net>
+Date:   Fri Aug 30 05:07:36 2024 -0700
+
+    [lib] Remove `inline` from variable templates (#7240)
+
+commit c001805bb769fe237034151d59ddd20835a17298
+Author: A. Jiang <de34@live.cn>
+Date:   Fri Aug 30 20:52:00 2024 +0800
+
+    [lib] Remove `friend class X` (#6427)
+
+    Friendship between library classes is considered an implementation detail.
+
+commit 1fafde9a04a3760debb932839791b1d2047ba432
+Author: A. Jiang <de34@live.cn>
+Date:   Fri Aug 30 20:52:49 2024 +0800
+
+    [fs.class.directory.entry.general] Remove superfluous "unneeded" (#7245)
+
+commit e010cf6cde64a498c2bc4291e7e79e66e8ace79a
+Author: Vlad Serebrennikov <serebrennikov.vladislav@gmail.com>
+Date:   Fri Aug 23 21:03:51 2024 +0400
+
+    [basic.scope.scope] Fix a note about declarations that do not bind names
+
+    The note is saying that declarations of qualified names do not bind names, but this is not supported by normative wording in [dcl.meaning]
+
+commit 36a1f39068e71d69e4ca534c5b72891055675e88
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Wed Sep 4 10:23:14 2024 -0400
+
+    [forward.list] Replace misplaced comma with period (#7246)
+
+commit f23059bf704a48b4805db28441ec73b61054ab9d
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Sep 5 00:03:56 2024 +0800
+
+    [optional.syn] Use `decay_t<T>` directly instead of "see below" (#7247)
+
+commit 9d9a3777f1a571dd2648023fe70848c32aebda09
+Author: Casey Carter <Casey@Carter.net>
+Date:   Sun Sep 8 12:13:53 2024 -0700
+
+    [associative.reqmts.general,unord.req.general] Fix cross-references to [container.alloc.reqmts] and [container.reqmts] (#7249)
+
+    Both paragraphs incorrectly point to [container.reqmts] instead of [container.alloc.reqmts] for "the requirements of an allocator-aware container".
+
+commit d930c5fa6728dd0b599f9c7918a2f0a0f747aaa2
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Mon Sep 16 20:35:33 2024 +0200
+
+    [expr.delete] Remove stray "the" between words (#7253)
+
+commit 9243ba5befaea8fd3e878e6114942db8d556a6e0
+Author: Steve Downey <sdowney@gmail.com>
+Date:   Tue Sep 17 06:13:18 2024 -0400
+
+    [optional.assign] Use itemized list for operator=(U&& v) constraints (#7255)
+
+commit 4930897a2a45fa57fd9d766a24229a9e3f14f23e
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Aug 21 13:58:22 2021 +0200
+
+    [dcl.spec.general,dcl.fct.spec] Clarify duplication of decl-specifiers
+
+commit d0c00bf629f4b91d19176c2397aa3ff7c1c0ce63
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Sep 26 18:49:15 2024 +0200
+
+    [tab:lex.charset.literal] Shorten table heading
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 945b1c071ed511d11a2152aa70e08290f91a7856
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Sep 26 19:11:58 2024 +0200
+
+    [tab:re.matchflag] Shorten table heading
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 4e34492bc7279fedb0e066f4925860e686fa81dc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Sep 26 19:43:50 2024 +0200
+
+    [rand.req] Fix table headers for longtable continued on following page
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 2b1e6d2952987bf4ada8275212a7bb297bb0c1c7
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Sep 26 20:19:01 2024 +0200
+
+    [macros] Fix duplicate vertical lines visible in tables in [optional.assign]
+
+    Fixes ISO/CS comment (C++23 proof)
+
+commit 0680a08ee677e0970b4460fd614f58b122845047
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Thu Sep 26 21:59:34 2024 +0100
+
+    [ios.init] Remove unused Init::init_cnt static member (#7263)
+
+    The text that made use of this variable was removed by LWG1123 and has
+    not been present in the WP since N3090. The effects of Init construction
+    and destruction are specified entirely without the use of this variable,
+    so it serves no purpose now.
+
+commit afdd158f555892507bc44c6d372c3b45a7f09832
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Sep 27 00:09:11 2024 +0200
+
+    [styles] Format title of \codeblocktu using 'caption' package
+
+    This restores the C++20 status of the formatting.
+
+commit 2b3e09e2cc773b7205310917c5a6b2bdd87340af
+Author: Casey Carter <Casey@Carter.net>
+Date:   Tue Oct 1 03:22:29 2024 -0700
+
+    [inplace.vector.cons] "Constructs an object" is redundant (#7252)
+
+commit 70954edf0b2c915d9b2ca4a1cff99b1c1cba2089
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Oct 1 23:09:04 2024 -0400
+
+    [depr.lit] Fix grammar according to P2361R6
+
+    P2361R6 introduced the notion of unevaluated strings, and
+    updated the grammar for literal operator function accodingly.
+    Unfortunely, the corresponding grammar reference that was
+    deprecated was not similarly updated.
+
+commit 08b167d5476c9fd02a7a0484ae031cb358a99ddf
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Sat Oct 5 22:24:02 2024 +0100
+
+    [priqueue.cons.alloc] Add missing initialization for comp (#7291)
+
+    This is consistent with p2 and p8 which also value-initialize it.
+
+commit 738b14f990e0575a3ca63b579d87edb5a6133ffb
+Author: Casey Carter <Casey@Carter.net>
+Date:   Sat Oct 5 15:03:04 2024 -0700
+
+    [array.creation] Clarify "Mandates" for `to_array` overloads (#7286)
+
+    It's confusing that these `to_array` overloads require `T` to be constructible from various types, when they actually construct `remove_cv_t<T>` objects. We experts know that initialization doesn't depend on the cv-qualification of the target type ([dcl.init.general]/16), but there's no need to make readers jump through hoops to understand the spec.
+
+commit d5c9f2d248860e8e7de78f595b93a8b01c7e02c8
+Author: Lewis Baker <lewissbaker@users.noreply.github.com>
+Date:   Tue Oct 8 21:07:48 2024 +1030
+
+    [exec.split,exec.when.all] Fix typo stop_callback_of_t -> stop_callback_for_t (#7295)
+
+commit 58c01ba5765e8c91ce4aab462d25247167a7e481
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue Oct 8 11:38:42 2024 +0100
+
+    [re.grammar] Add missing backslash to UnicodeEscapeSequence example (#7290)
+
+commit ebef68dd9f1c3bccfe06d14eb83c05a7a35dcec3
+Author: Lewis Baker <lewissbaker@users.noreply.github.com>
+Date:   Tue Oct 8 22:06:23 2024 +1030
+
+    [exec.just] Add missing LaTeX escape for product-type construction (#7216)
+
+commit 7ea8f59e19842e720360f15b64c2199ea27641ac
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Oct 10 17:53:54 2024 +0800
+
+    [mutex.syn] Add missing ',' for consistency
+
+commit 7c6322a59e3359c5002357831328b25939cd5383
+Author: Lewis Baker <lewissbaker@users.noreply.github.com>
+Date:   Sun Oct 13 04:07:30 2024 +1030
+
+    [stoptoken.concepts] Remove redundant 'swappable<Token>' clause from 'stoppable_token' concept (#7299)
+
+    The `stoppable_token<Token>` concept requires both `copyable<Token>` and `swappable<Token>`. However, the `copyable<Token>` requirement already subsumes `movable<Token>`, which subsumes `swappable<Token>`.
+
+    Therefore the requirement for `swappable<Token>` can be removed from the `stoppable_token` concept definition with no semantic change.
+
+commit 9bf42221ab5a52ef10cb980a22e8a9617dbbf18b
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sat Oct 12 22:39:57 2024 +0200
+
+    [rcu.syn] Add missing ',' in comment (#7301)
+
+commit a0411db859cf1eabc2be24a5d2add4eaf288dac5
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Oct 14 12:30:30 2024 +0200
+
+    [expr.const] Add paragraph number for general example
+
+commit 3982d5d5758df949e3c2e0174c72758189be6f2e
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Mon Oct 14 08:54:22 2024 -0400
+
+    [except.ctor] Retitle subclause as 'stack unwinding' (#7282)
+
+    The purpose of this subclause is to define stack unwinding,
+    which in specified in terms of the lifetime of objects, not
+    just class types.  Hence, while much of the text is addressing
+    interactions with contructors and destructors (the original
+    subclause title) it does more than just that.
+
+commit 4eb30d3d618ef44ae3925a1a62090bbbbfe8cabf
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Oct 16 07:39:15 2024 -0400
+
+    [cpp.subst] change "proprocessing file" to "translation unit" (#7293)
+
+    The term 'preprocessing translation unit' is defined in [lex.separate]
+    while the term 'preprocessing file' is never defined, and is
+    not used anywhere else in the standard.  Prefer to use the
+    specified term, as it reasonably covers this case.
+
+commit 40228c690cb8d2ac27bd54bdddeabe425bd022b2
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Oct 16 07:40:20 2024 -0400
+
+    [cpp.import] Change "directive" to "definition" in "active macro directive" (#7292)
+
+    The term 'active macro directive' is defined in p6, but never used.
+    Meanwhile, there are multiple uses of 'active macro definition' but
+    that term is never defined, including in the very sentence following
+    the definition of the unused term, and in other clauses that
+    cross-reference to this clause for their definition.
+
+commit 47da0e8b88bf1aa20aa474edf04a6d29e70b7563
+Author: Anders Schau Knatten <anders@knatten.org>
+Date:   Wed Oct 16 13:41:26 2024 +0200
+
+    [over.oper.general] Change "basic type" to "fundamental type" (#7287)
+
+    The term "basic type" is used twice in this note but it's never defined anywhere, nor used.
+
+commit 7fe7519a5af674cd914344c650529f743fd92fc2
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Oct 1 22:13:53 2024 -0400
+
+    [except.handle] Remove confusing comparison to variadic functions
+
+    The analogy that the ellipsis in an exception handler was similar to an
+    ellipsis in a function declaration may have made sense at one time, but
+    the comparison with a syntax using a macro based API calling 'va_arg'
+    to access its contents --- something that is not possible for an
+    exception handler --- seems more confusing than helpful today.
+
+commit d225f51f8cb799fb014cb73beb7dcccc044392cc
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue Aug 20 11:58:24 2024 +0100
+
+    [text.encoding.aliases] Add note about what isn't required
+
+    Make it explicit that `copyable` is intended, rather than `semiregular`,
+    and that the return types of `begin()` and `end()` can differ.
+
+    Also remove a FIXME comment for something that doesn't need fixing.
+    These requirements on a type are specified in our usual form, it would
+    be wrong to use _Remarks_: or _Requires_: here.
+
+commit 6338d95ae620f5e4d37d27a39a40f9de9af37b77
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Oct 16 08:47:02 2024 -0400
+
+    [lex.charset] Introduce parent subclause [lex.char] for character sets and UCNs (#7067)
+
+    The grammar for universal-character-name is oddly sandwiched into the
+    middle of the subclause talking about the different character sets used
+    by the standard.  To improve the flow, extract that grammar into its own
+    subclause.
+
+    In the extraction, I make three other clarifying changes.  First, describe
+    this new subclause as 'a way to name any element of the of the translation
+    character set using just the basic character set' rather than simply
+    'a way to name other characters'. Then, merge the sentence on where universal
+    characters are prohibited into the new intro sentence describing universal
+    characters, to make clear that there is no contradiction between nominating
+    a character, and how that character can be used. Finally, remove the 'one of'
+    in the grammar where there is only one option to choose.
+
+commit 9b6b757f34bf4a1eeb6a66481a444b83f1ee5770
+Author: Matthias Kretz <m.kretz@gsi.de>
+Date:   Thu Sep 12 21:41:02 2024 +0200
+
+    [sf.cmath.assoc.laguerre,sf.cmath.assoc.legendre] Add reference to eq
+
+    The associated Laguerre/Legendre functions build on the
+    Laguerre/Legendre functions, which are defined in different equations.
+    Point to them from the associated functions.
+
+    Also use the correct \ell as used in the formula.
+
+commit 0456a32e41772b0a68b4055fb4e6533cb64e0e3d
+Author: Yihe Li <winmikedows@hotmail.com>
+Date:   Thu Sep 5 23:59:58 2024 +0800
+
+    [utility.syn, flat.map.defn] Remove all [[nodiscard]] from library wording
+
+commit 8b2c7fc3c58bd109c82a016ee2cc5b691bdcd853
+Author: Eisenwave <me@eisenwave.net>
+Date:   Mon Jun 10 23:22:04 2024 +0200
+
+    [expr.new] Extend example for new-expressions with zero size arrays
+
+commit fb34daf31b53389cc35b3f5f65a69785fc6dd1de
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Jul 23 22:32:52 2024 -0400
+
+    [char.traits] Better cross-reference several headers
+
+commit 220cb742e8056ad033ad8dce5630d7d3acaa4c7d
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 15:37:39 2024 +0100
+
+    [debugging] Move [debugging] to the end of Clause [diagnostics]
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit 7a2dafa6b4cca842e264bfd544b69452fb448c39
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 15:43:39 2024 +0100
+
+    [execpol] Move [execpol] to the end of subclause [algorithms.parallel]
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit 93e2e1c6bcf5e9c3e551d964978e8bf241c392a4
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 15:52:54 2024 +0100
+
+    [type.index] Move [type.index] into subclause [support.rtti]
+
+    The subclause is integrated into the structure of [support.rtti],
+    meaning that the synopsis becomes a sibling of the rest, and the
+    subdivisions of the remaining text are removed (in analogy with
+    [type.info]).
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit cdb120a4aee270f4e6e40dd7b07885c70651224e
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 17:25:51 2024 +0100
+
+    [containers] Move synopses right in front of the classes they define
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit b7e389c9feca4839f77ad60985f509e01f96a399
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 15:27:06 2024 +0100
+
+    [std] Reorder clauses: [algorithm], [strings]
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit 5512050c2db44d87566d25ce4f70b530624cb330
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 15:36:47 2024 +0100
+
+    [std] Create new top-level Clause [text], following [strings]
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit fc6f670832980fc7b8219cb6945592cbe45d9239
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 19:01:21 2024 +0100
+
+    [text, re] Move [re] into [text]
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit 5d106373aada591874ab5e38301502b3012e0502
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 19:06:03 2024 +0100
+
+    [text, localization] Move [localization] into [text]
+
+    The subclause [text.encodings] is extracted and elevated to a sibling
+    subclause of [localization].
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit 804846a56f7e73dafe4ebd621fa81097d2e94603
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 20:15:42 2024 +0100
+
+    [charconv, format] Move [charconv], [format] to [text]
+
+    Part of the C++26 clause restructuring (#5315).
+
+commit 4b1a9a76c29c31cc3f679a8bdb1603842baf3501
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 20:31:33 2024 +0100
+
+    [text, c.strings] Move text-related parts of [c.strings] to [text]
+
+    The text-related subclauses [cctype.syn], [cwctype.syn], [cwchar.syn],
+    [cuchar.syn], and [c.mb.wcs] are moved to a new subclause [text.c.strings].
+
+    Part of the C++26 clause restructuring (#5226, #5315).
+
+commit 8003b627a7e336c2e9f350a3bb1ad395ec7c1cc7
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Wed Oct 16 19:41:35 2024 +0000
+
+    [expr, temp.arg.nontype] Use 'pointer to' instead of 'address of' (#6174)
+
+    Specifically, in:
+     * [expr.prim.lambda.closure]p8, p11
+     * [expr.const]p13.3
+     * [temp.arg.nontype]p3
+
+commit 198e991fed47efcd8b7fe1ad98ecde4d8722a201
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Oct 2 15:55:49 2024 -0400
+
+    [except.handle] group all paragraphs on searching for handler
+
+    This commit moves all of the paragraphs involved in the search for a
+    handler for an exception into a single logical sequence.
+
+    After this change, [except.spec] deals only with specifying the
+    'noexcept' function decorator and its interaction with the
+    'noexcept' operator, and contains no text regarding exceptions
+    themselves.  It might be appropriate to move that subclause into
+    the [dcl] structure at a future date.
+
+ + diff --git a/papers/n4994.md b/papers/n4994.md new file mode 100644 index 0000000000..223aaa59bd --- /dev/null +++ b/papers/n4994.md @@ -0,0 +1,590 @@ +# N4994 Editors' Report -- Programming Languages -- C++ + +Date: 2024-10-16 + +Thomas Köppe (editor, Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor, Bright Side Computing, LLC) +Richard Smith (co-editor, Google Inc) + +Email: `cxxeditor@gmail.com` + +## Acknowledgements + +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 + + * [N4993](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4993.pdf) is the + current working draft for C++26. It replaces + [N4988](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf). + * N4994 is this Editors' Report. + +## Draft approval + +The previous drafts +[N4986](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4986.pdf) +and +[N4988](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf) +were not approved at any WG21 meeting. For approval of this draft, N4993, +please consult the previous Editors' reports +[N4987](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4987.html) +and +[N4989](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4989.html) +as well as this one. + +## No motions + +There have been no new, approved WG21 motions. +This revision contains only editorial changes. + +A few of the editorial changes fix mistakes in our LaTeX sources that were +reported to us by the ISO secretariat during the ongoing publication of C++23. + +## Editorial changes + +### Major editorial changes + +For this revision, we have reorganised several clauses and subclauses. +As a reminder: the editorial team aims to perform only one major reorganisation +that changes top-level clause numbers per C++ revision, and this is it for C++26. + +The changes create a new clause "Text processing library `[text]`" that collects +formatting, conversions, locales, regular expressions, and text-related C library +facilities. Clauses are rearranged as: + + * Algorithms library `[algorithms]` + * Strings library `[strings]` + * Text processing library `[text]` + * Numerics library `[numerics]` + * Time library `[time]` + * Input/output library `[input.output]` + +The new `[text]` clause obtains the following contents: + + * Primitive numeric conversions `[charconv]`, from `[utilities]` + * Formatting `[format]`, from `[utilities]` + * Text encodings identification `[text.encoding]`, extracted from `[localization]` + * Localization library `[localization]` + * Regular expressions library `[re]` + * C library facilities `[cctype.syn]`, `[cwctype.syn]`, `[cwchar.syn]`, `[cuchar.syn]`, and `[c.mb.wcs]` + +Additionally, the following subclauses are moved: + +* Debugging `[debugging]` from `[utilities]` to the end of `[diagnostics]` +* Execution policies `[execpol]` from `[utilities]` to the end of `[algorithms.parallel]` +* Class `type_index` `[type.index]` from `[utilities]` to `[support.rtti]` + +This removes a number of unrelated clauses from the large `[utilities]` clause. + +Finally, we spread the synopses in `[containers]` out to appear right in front +of the classes they define. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N4988 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/n4988...n4993). + + commit 15a43d522467d389bd9340081d65dbf17d44d255 + Author: Thomas Köppe + Date: Mon Aug 5 12:21:56 2024 +0100 + + [temp.over.link] Reword to clarify that declarations correspond (#5999) + + commit 3c0f4cf0a03892157ebf3a472d3e9450a41f038e + Author: Lewis Baker + Date: Sun Aug 4 09:26:26 2024 +0930 + + [snd.expos] Fix typo in definition of SCHED-ENV exposition-only helper + + Change `o1` -> `o2` to reference the expression declared as part of the definition of `SCHED-ENV`. + + commit 5056b86597f5ba9278601db46a415f2d76e1bc8f + Author: Jens Maurer + Date: Fri Aug 2 17:38:05 2024 +0200 + + [temp.constr.order] Reflect fold expanded constraints in footnotes + + commit c92bc384b118412322f9893832508bf17f46f644 + Author: Jens Maurer + Date: Thu Aug 1 12:35:50 2024 +0200 + + [dcl.fct] Fix obsolete phrasing when defining 'function type' + + commit fabbff2d812e0a99bd1162460812ec2f5399636e + Author: Arthur O'Dwyer + Date: Thu Aug 8 17:15:39 2024 -0400 + + [sequences] Consistent comma in "If X, there are no effects" (#7139) + + commit 04c5a0c509dbf8f9f81223d1de5bb917cd3074c5 + Author: Hana Dusíková + Date: Tue Aug 20 12:21:43 2024 +0200 + + [meta.const.eval] Fix function declaration in example (#7234) + + commit ab4c0663dc72f09fb8ef6c366352c9d1a68e8fa9 + Author: Vlad Serebrennikov + Date: Fri Aug 23 22:06:05 2024 +0400 + + [expr.prim.lambda.capture] Incorporate ellipsis into "captured by copy" definition + + commit 6ea6df4c96653d6696bb0133253ea0159b0f278f + Author: Vlad Serebrennikov + Date: Sat Aug 24 23:24:01 2024 +0400 + + [dcl.type.elab] Remove redundant full stop (#7242) + + commit 24ceda755967b022e8e089d4f0cdcf4bc99a4adb + Author: Hewill Kang + Date: Mon Aug 26 18:29:28 2024 +0800 + + [exec.snd.apply,exec.schedule.from] Properly mark "see below" (#7210) + + commit 447b6291061d50a582f72dd42d9d6265857ded5c + Author: Joachim Wuttke + Date: Mon Aug 26 22:30:39 2024 +0200 + + [numerics] Correct typo Bessell -> Bessel (#7244) + + commit db0ca108a9b44ef8f06338ecf68f1e4653be4267 + Author: Arthur O'Dwyer + Date: Thu Aug 29 06:13:18 2024 -0400 + + [inplace.vector] Fix some spelling/grammar issues (#7243) + + commit 21e477fb6dbfa7813eb2263bfa31c748bdce589b + Author: Casey Carter + Date: Fri Aug 30 05:07:36 2024 -0700 + + [lib] Remove `inline` from variable templates (#7240) + + commit c001805bb769fe237034151d59ddd20835a17298 + Author: A. Jiang + Date: Fri Aug 30 20:52:00 2024 +0800 + + [lib] Remove `friend class X` (#6427) + + Friendship between library classes is considered an implementation detail. + + commit 1fafde9a04a3760debb932839791b1d2047ba432 + Author: A. Jiang + Date: Fri Aug 30 20:52:49 2024 +0800 + + [fs.class.directory.entry.general] Remove superfluous "unneeded" (#7245) + + commit e010cf6cde64a498c2bc4291e7e79e66e8ace79a + Author: Vlad Serebrennikov + Date: Fri Aug 23 21:03:51 2024 +0400 + + [basic.scope.scope] Fix a note about declarations that do not bind names + + The note is saying that declarations of qualified names do not bind names, but this is not supported by normative wording in [dcl.meaning] + + commit 36a1f39068e71d69e4ca534c5b72891055675e88 + Author: Arthur O'Dwyer + Date: Wed Sep 4 10:23:14 2024 -0400 + + [forward.list] Replace misplaced comma with period (#7246) + + commit f23059bf704a48b4805db28441ec73b61054ab9d + Author: A. Jiang + Date: Thu Sep 5 00:03:56 2024 +0800 + + [optional.syn] Use `decay_t` directly instead of "see below" (#7247) + + commit 9d9a3777f1a571dd2648023fe70848c32aebda09 + Author: Casey Carter + Date: Sun Sep 8 12:13:53 2024 -0700 + + [associative.reqmts.general,unord.req.general] Fix cross-references to [container.alloc.reqmts] and [container.reqmts] (#7249) + + Both paragraphs incorrectly point to [container.reqmts] instead of [container.alloc.reqmts] for "the requirements of an allocator-aware container". + + commit d930c5fa6728dd0b599f9c7918a2f0a0f747aaa2 + Author: Jan Schultke + Date: Mon Sep 16 20:35:33 2024 +0200 + + [expr.delete] Remove stray "the" between words (#7253) + + commit 9243ba5befaea8fd3e878e6114942db8d556a6e0 + Author: Steve Downey + Date: Tue Sep 17 06:13:18 2024 -0400 + + [optional.assign] Use itemized list for operator=(U&& v) constraints (#7255) + + commit 4930897a2a45fa57fd9d766a24229a9e3f14f23e + Author: Jens Maurer + Date: Sat Aug 21 13:58:22 2021 +0200 + + [dcl.spec.general,dcl.fct.spec] Clarify duplication of decl-specifiers + + commit d0c00bf629f4b91d19176c2397aa3ff7c1c0ce63 + Author: Jens Maurer + Date: Thu Sep 26 18:49:15 2024 +0200 + + [tab:lex.charset.literal] Shorten table heading + + Fixes ISO/CS comment (C++23 proof) + + commit 945b1c071ed511d11a2152aa70e08290f91a7856 + Author: Jens Maurer + Date: Thu Sep 26 19:11:58 2024 +0200 + + [tab:re.matchflag] Shorten table heading + + Fixes ISO/CS comment (C++23 proof) + + commit 4e34492bc7279fedb0e066f4925860e686fa81dc + Author: Jens Maurer + Date: Thu Sep 26 19:43:50 2024 +0200 + + [rand.req] Fix table headers for longtable continued on following page + + Fixes ISO/CS comment (C++23 proof) + + commit 2b1e6d2952987bf4ada8275212a7bb297bb0c1c7 + Author: Jens Maurer + Date: Thu Sep 26 20:19:01 2024 +0200 + + [macros] Fix duplicate vertical lines visible in tables in [optional.assign] + + Fixes ISO/CS comment (C++23 proof) + + commit 0680a08ee677e0970b4460fd614f58b122845047 + Author: Jonathan Wakely + Date: Thu Sep 26 21:59:34 2024 +0100 + + [ios.init] Remove unused Init::init_cnt static member (#7263) + + The text that made use of this variable was removed by LWG1123 and has + not been present in the WP since N3090. The effects of Init construction + and destruction are specified entirely without the use of this variable, + so it serves no purpose now. + + commit afdd158f555892507bc44c6d372c3b45a7f09832 + Author: Jens Maurer + Date: Fri Sep 27 00:09:11 2024 +0200 + + [styles] Format title of \codeblocktu using 'caption' package + + This restores the C++20 status of the formatting. + + commit 2b3e09e2cc773b7205310917c5a6b2bdd87340af + Author: Casey Carter + Date: Tue Oct 1 03:22:29 2024 -0700 + + [inplace.vector.cons] "Constructs an object" is redundant (#7252) + + commit 70954edf0b2c915d9b2ca4a1cff99b1c1cba2089 + Author: Alisdair Meredith + Date: Tue Oct 1 23:09:04 2024 -0400 + + [depr.lit] Fix grammar according to P2361R6 + + P2361R6 introduced the notion of unevaluated strings, and + updated the grammar for literal operator function accodingly. + Unfortunely, the corresponding grammar reference that was + deprecated was not similarly updated. + + commit 08b167d5476c9fd02a7a0484ae031cb358a99ddf + Author: Jonathan Wakely + Date: Sat Oct 5 22:24:02 2024 +0100 + + [priqueue.cons.alloc] Add missing initialization for comp (#7291) + + This is consistent with p2 and p8 which also value-initialize it. + + commit 738b14f990e0575a3ca63b579d87edb5a6133ffb + Author: Casey Carter + Date: Sat Oct 5 15:03:04 2024 -0700 + + [array.creation] Clarify "Mandates" for `to_array` overloads (#7286) + + It's confusing that these `to_array` overloads require `T` to be constructible from various types, when they actually construct `remove_cv_t` objects. We experts know that initialization doesn't depend on the cv-qualification of the target type ([dcl.init.general]/16), but there's no need to make readers jump through hoops to understand the spec. + + commit d5c9f2d248860e8e7de78f595b93a8b01c7e02c8 + Author: Lewis Baker + Date: Tue Oct 8 21:07:48 2024 +1030 + + [exec.split,exec.when.all] Fix typo stop_callback_of_t -> stop_callback_for_t (#7295) + + commit 58c01ba5765e8c91ce4aab462d25247167a7e481 + Author: Jonathan Wakely + Date: Tue Oct 8 11:38:42 2024 +0100 + + [re.grammar] Add missing backslash to UnicodeEscapeSequence example (#7290) + + commit ebef68dd9f1c3bccfe06d14eb83c05a7a35dcec3 + Author: Lewis Baker + Date: Tue Oct 8 22:06:23 2024 +1030 + + [exec.just] Add missing LaTeX escape for product-type construction (#7216) + + commit 7ea8f59e19842e720360f15b64c2199ea27641ac + Author: A. Jiang + Date: Thu Oct 10 17:53:54 2024 +0800 + + [mutex.syn] Add missing ',' for consistency + + commit 7c6322a59e3359c5002357831328b25939cd5383 + Author: Lewis Baker + Date: Sun Oct 13 04:07:30 2024 +1030 + + [stoptoken.concepts] Remove redundant 'swappable' clause from 'stoppable_token' concept (#7299) + + The `stoppable_token` concept requires both `copyable` and `swappable`. However, the `copyable` requirement already subsumes `movable`, which subsumes `swappable`. + + Therefore the requirement for `swappable` can be removed from the `stoppable_token` concept definition with no semantic change. + + commit 9bf42221ab5a52ef10cb980a22e8a9617dbbf18b + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sat Oct 12 22:39:57 2024 +0200 + + [rcu.syn] Add missing ',' in comment (#7301) + + commit a0411db859cf1eabc2be24a5d2add4eaf288dac5 + Author: Jens Maurer + Date: Mon Oct 14 12:30:30 2024 +0200 + + [expr.const] Add paragraph number for general example + + commit 3982d5d5758df949e3c2e0174c72758189be6f2e + Author: Alisdair Meredith + Date: Mon Oct 14 08:54:22 2024 -0400 + + [except.ctor] Retitle subclause as 'stack unwinding' (#7282) + + The purpose of this subclause is to define stack unwinding, + which in specified in terms of the lifetime of objects, not + just class types. Hence, while much of the text is addressing + interactions with contructors and destructors (the original + subclause title) it does more than just that. + + commit 4eb30d3d618ef44ae3925a1a62090bbbbfe8cabf + Author: Alisdair Meredith + Date: Wed Oct 16 07:39:15 2024 -0400 + + [cpp.subst] change "proprocessing file" to "translation unit" (#7293) + + The term 'preprocessing translation unit' is defined in [lex.separate] + while the term 'preprocessing file' is never defined, and is + not used anywhere else in the standard. Prefer to use the + specified term, as it reasonably covers this case. + + commit 40228c690cb8d2ac27bd54bdddeabe425bd022b2 + Author: Alisdair Meredith + Date: Wed Oct 16 07:40:20 2024 -0400 + + [cpp.import] Change "directive" to "definition" in "active macro directive" (#7292) + + The term 'active macro directive' is defined in p6, but never used. + Meanwhile, there are multiple uses of 'active macro definition' but + that term is never defined, including in the very sentence following + the definition of the unused term, and in other clauses that + cross-reference to this clause for their definition. + + commit 47da0e8b88bf1aa20aa474edf04a6d29e70b7563 + Author: Anders Schau Knatten + Date: Wed Oct 16 13:41:26 2024 +0200 + + [over.oper.general] Change "basic type" to "fundamental type" (#7287) + + The term "basic type" is used twice in this note but it's never defined anywhere, nor used. + + commit 7fe7519a5af674cd914344c650529f743fd92fc2 + Author: Alisdair Meredith + Date: Tue Oct 1 22:13:53 2024 -0400 + + [except.handle] Remove confusing comparison to variadic functions + + The analogy that the ellipsis in an exception handler was similar to an + ellipsis in a function declaration may have made sense at one time, but + the comparison with a syntax using a macro based API calling 'va_arg' + to access its contents --- something that is not possible for an + exception handler --- seems more confusing than helpful today. + + commit d225f51f8cb799fb014cb73beb7dcccc044392cc + Author: Jonathan Wakely + Date: Tue Aug 20 11:58:24 2024 +0100 + + [text.encoding.aliases] Add note about what isn't required + + Make it explicit that `copyable` is intended, rather than `semiregular`, + and that the return types of `begin()` and `end()` can differ. + + Also remove a FIXME comment for something that doesn't need fixing. + These requirements on a type are specified in our usual form, it would + be wrong to use _Remarks_: or _Requires_: here. + + commit 6338d95ae620f5e4d37d27a39a40f9de9af37b77 + Author: Alisdair Meredith + Date: Wed Oct 16 08:47:02 2024 -0400 + + [lex.charset] Introduce parent subclause [lex.char] for character sets and UCNs (#7067) + + The grammar for universal-character-name is oddly sandwiched into the + middle of the subclause talking about the different character sets used + by the standard. To improve the flow, extract that grammar into its own + subclause. + + In the extraction, I make three other clarifying changes. First, describe + this new subclause as 'a way to name any element of the of the translation + character set using just the basic character set' rather than simply + 'a way to name other characters'. Then, merge the sentence on where universal + characters are prohibited into the new intro sentence describing universal + characters, to make clear that there is no contradiction between nominating + a character, and how that character can be used. Finally, remove the 'one of' + in the grammar where there is only one option to choose. + + commit 9b6b757f34bf4a1eeb6a66481a444b83f1ee5770 + Author: Matthias Kretz + Date: Thu Sep 12 21:41:02 2024 +0200 + + [sf.cmath.assoc.laguerre,sf.cmath.assoc.legendre] Add reference to eq + + The associated Laguerre/Legendre functions build on the + Laguerre/Legendre functions, which are defined in different equations. + Point to them from the associated functions. + + Also use the correct \ell as used in the formula. + + commit 0456a32e41772b0a68b4055fb4e6533cb64e0e3d + Author: Yihe Li + Date: Thu Sep 5 23:59:58 2024 +0800 + + [utility.syn, flat.map.defn] Remove all [[nodiscard]] from library wording + + commit 8b2c7fc3c58bd109c82a016ee2cc5b691bdcd853 + Author: Eisenwave + Date: Mon Jun 10 23:22:04 2024 +0200 + + [expr.new] Extend example for new-expressions with zero size arrays + + commit fb34daf31b53389cc35b3f5f65a69785fc6dd1de + Author: Alisdair Meredith + Date: Tue Jul 23 22:32:52 2024 -0400 + + [char.traits] Better cross-reference several headers + + commit 220cb742e8056ad033ad8dce5630d7d3acaa4c7d + Author: Thomas Köppe + Date: Wed Oct 16 15:37:39 2024 +0100 + + [debugging] Move [debugging] to the end of Clause [diagnostics] + + Part of the C++26 clause restructuring (#5315). + + commit 7a2dafa6b4cca842e264bfd544b69452fb448c39 + Author: Thomas Köppe + Date: Wed Oct 16 15:43:39 2024 +0100 + + [execpol] Move [execpol] to the end of subclause [algorithms.parallel] + + Part of the C++26 clause restructuring (#5315). + + commit 93e2e1c6bcf5e9c3e551d964978e8bf241c392a4 + Author: Thomas Köppe + Date: Wed Oct 16 15:52:54 2024 +0100 + + [type.index] Move [type.index] into subclause [support.rtti] + + The subclause is integrated into the structure of [support.rtti], + meaning that the synopsis becomes a sibling of the rest, and the + subdivisions of the remaining text are removed (in analogy with + [type.info]). + + Part of the C++26 clause restructuring (#5315). + + commit cdb120a4aee270f4e6e40dd7b07885c70651224e + Author: Thomas Köppe + Date: Wed Oct 16 17:25:51 2024 +0100 + + [containers] Move synopses right in front of the classes they define + + Part of the C++26 clause restructuring (#5315). + + commit b7e389c9feca4839f77ad60985f509e01f96a399 + Author: Thomas Köppe + Date: Wed Oct 16 15:27:06 2024 +0100 + + [std] Reorder clauses: [algorithm], [strings] + + Part of the C++26 clause restructuring (#5315). + + commit 5512050c2db44d87566d25ce4f70b530624cb330 + Author: Thomas Köppe + Date: Wed Oct 16 15:36:47 2024 +0100 + + [std] Create new top-level Clause [text], following [strings] + + Part of the C++26 clause restructuring (#5315). + + commit fc6f670832980fc7b8219cb6945592cbe45d9239 + Author: Thomas Köppe + Date: Wed Oct 16 19:01:21 2024 +0100 + + [text, re] Move [re] into [text] + + Part of the C++26 clause restructuring (#5315). + + commit 5d106373aada591874ab5e38301502b3012e0502 + Author: Thomas Köppe + Date: Wed Oct 16 19:06:03 2024 +0100 + + [text, localization] Move [localization] into [text] + + The subclause [text.encodings] is extracted and elevated to a sibling + subclause of [localization]. + + Part of the C++26 clause restructuring (#5315). + + commit 804846a56f7e73dafe4ebd621fa81097d2e94603 + Author: Thomas Köppe + Date: Wed Oct 16 20:15:42 2024 +0100 + + [charconv, format] Move [charconv], [format] to [text] + + Part of the C++26 clause restructuring (#5315). + + commit 4b1a9a76c29c31cc3f679a8bdb1603842baf3501 + Author: Thomas Köppe + Date: Wed Oct 16 20:31:33 2024 +0100 + + [text, c.strings] Move text-related parts of [c.strings] to [text] + + The text-related subclauses [cctype.syn], [cwctype.syn], [cwchar.syn], + [cuchar.syn], and [c.mb.wcs] are moved to a new subclause [text.c.strings]. + + Part of the C++26 clause restructuring (#5226, #5315). + + commit 8003b627a7e336c2e9f350a3bb1ad395ec7c1cc7 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Wed Oct 16 19:41:35 2024 +0000 + + [expr, temp.arg.nontype] Use 'pointer to' instead of 'address of' (#6174) + + Specifically, in: + * [expr.prim.lambda.closure]p8, p11 + * [expr.const]p13.3 + * [temp.arg.nontype]p3 + + commit 198e991fed47efcd8b7fe1ad98ecde4d8722a201 + Author: Alisdair Meredith + Date: Wed Oct 2 15:55:49 2024 -0400 + + [except.handle] group all paragraphs on searching for handler + + This commit moves all of the paragraphs involved in the search for a + handler for an exception into a single logical sequence. + + After this change, [except.spec] deals only with specifying the + 'noexcept' function decorator and its interaction with the + 'noexcept' operator, and contains no text regarding exceptions + themselves. It might be appropriate to move that subclause into + the [dcl] structure at a future date. diff --git a/papers/n5002.html b/papers/n5002.html new file mode 100644 index 0000000000..0c4835ed67 --- /dev/null +++ b/papers/n5002.html @@ -0,0 +1,839 @@ + + + + + +N5002 + + +

N5002 Editors’ Report:
Programming Languages — C++

+ +

Date: 2024-12-17

+ +

Thomas Köppe (editor, Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor, Bright Side Computing, LLC)
+Richard Smith (co-editor, Google Inc)

+ +

Email: cxxeditor@gmail.com

+ +

Acknowledgements

+ +

Thanks to all those who have submitted editorial +issues +and to those who have provided pull requests with fixes. +Special thanks to Andreas Krug for many timely editorial fixes.

+ +

New papers

+ +
    +
  • N5001 is the +current working draft for C++26. It replaces +N4993.
  • +
  • N5002 is this Editors' Report.
  • +
+ +

Motions incorporated into working draft

+ +

Notes on motions

+ +

CWG Poll 9 was retracted.

+ +

Two LWG Polls, Poll 5 (P0472R2) and Poll 17 (P3019R11) have not been applied and +are being sent back to WG21 for clarification. We expect to see revisions to be +approved at the next meeting:

+ +
    +
  • LWG Poll 5 accidentally polled for the obsolete revision P0472R2 instead of the +intended P0472R3. It is sent back due to unclear intentions, with a request for +WG21 to clarify, and the expectation that R3 will be approved.

  • +
  • LWG Poll 17 caused technical discussion after the meeting, in which some +oversights were observed. The paper authors and the LWG chair agreed that +further LWG review would be in everybody's best interest. The poll is sent back +due to unclear specification, with a request for WG21 to produce a revision, +which we expect to be approved at the next meeting.

  • +
+ +

In CWG Poll 1, issue CWG1965 contains no wording changes since it is subsumed by CWG2879.

+ +

Core working group polls

+ +

CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues in +P3524R0 +(Core Language Working Group "ready" Issues for the November, 2024 meeting) to the C++ Working Paper.

+ +

CWG Poll 2. Apply the changes in +P3340R0 +(A Consistent Grammar for Sequences) to the C++ Working Paper.

+ +

CWG Poll 3. Apply the changes in +P2686R5 +(constexpr structured bindings and references to constexpr variables) to the C++ Working Paper.

+ +

CWG Poll 4. Apply the changes in +P3068R6 +(Allowing exception throwing in constant-evaluation) to the C++ Working Paper.

+ +

CWG Poll 5. Apply the changes in +P3247R2 +(Deprecate the notion of trivial types) to the C++ Working Paper.

+ +

CWG Poll 6. Apply the changes in +P2865R6 +(Remove Deprecated Array Comparisons from C++26) to the C++ Working Paper.

+ +

CWG Poll 7. Apply the changes in +P1061R10 +(Structured Bindings can introduce a Pack) to the C++ Working Paper.

+ +

CWG Poll 8. Apply the changes in +P3176R1 +(The Oxford variadic comma) to the C++ Working Paper.

+ +

CWG Poll 9 was retracted.

+ +

Library working group polls

+ +

LWG Poll 1. Apply the changes for all Ready and Tentatively Ready issues in +P3504R0 +(C++ Standard Library Ready Issues to be moved in Wrocław, Nov. 2024) to the C++ working paper.

+ +

LWG Poll 2. Apply the changes in +P3136R1 +(Retiring niebloids) to the C++ working paper.

+ +

LWG Poll 3. Apply the changes in +P3138R5 +(views::cache_latest) to the C++ working paper.

+ +

LWG Poll 4. Apply the changes in +P3379R0 +(Constrain std::expected equality operators) to the C++ working paper.

+ +

LWG Poll 5 was sent back (see above).

+ +

LWG Poll 6. Apply the changes in +P2862R1 +(text_encoding::name() should never return null values) to the C++ working paper.

+ +

LWG Poll 7. Apply the changes in +P2897R7 +(aligned_accessor: An mdspan accessor expressing pointer over-alignment) to the C++ working paper.

+ +

LWG Poll 8. Apply the changes in +P3355R1 +(Fix submdspan for C++26) to the C++ working paper.

+ +

LWG Poll 9. Apply the changes in +P3222R0 +(Fix C++26 by adding transposed special cases for P2642 layouts) to the C++ working paper.

+ +

LWG Poll 10. Apply the changes in +P3050R2 +(Fix C++26 by optimizing linalg::conjugated for noncomplex value types) to the C++ working paper.

+ +

LWG Poll 11. Apply the changes in +P3396R1 +(std::execution wording fixes) to the C++ working paper.

+ +

LWG Poll 12. Apply the changes in +P2835R7 +(Expose std::atomic_ref's object address) to the C++ working paper.

+ +

LWG Poll 13. Apply the changes in +P3323R1 +(cv-qualified types in atomic and atomic_ref) to the C++ working paper.

+ +

LWG Poll 14. Apply the changes in +P3508R0 +(Wording for "constexpr for specialized memory algorithms") and +P3369R0 +(constexpr for uninitialized_default_construct) to the C++ working paper.

+ +

LWG Poll 15. Apply the changes in +P3370R1 +(Add new library headers from C23) to the C++ working paper.

+ +

LWG Poll 16. Apply the changes in +P3309R3 +(constexpr atomic and atomic_ref) to the C++ working paper.

+ +

LWG Poll 17 was sent back (see above).

+ +

LWG Poll 18. Apply the changes in +P1928R15 +(std::simd — merge data-parallel types from the Parallelism TS 2) to the C++ working paper.

+ +

LWG Poll 19. Apply the changes in +P3325R5 +(A Utility for Creating Execution Environments) to the C++ working paper.

+ +

Editorial changes

+ +

Major editorial changes

+ +

There have not been any major editorial changes.

+ +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N4993 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 e9604bcd3d8325860a4db9d02c4f90d0ae70162e
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Oct 16 21:12:40 2024 +0100
+
+    [depr.format.syn] Fix header reference
+
+commit 0b296da823e7af4a987a0a870ae299420b9ae502
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Oct 17 00:39:04 2024 +0100
+
+    [{localization,re}.general] Change "This Clause" to "Subclause".
+
+    These subclauses are no longer top-level clauses.
+
+commit 629e10e2f4177dd24d513be71f2203de325a7e8a
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Thu Oct 17 08:57:39 2024 +0200
+
+    [inplace.vector.overview] Add missing ',' in comment
+
+commit 726e07a3a99a87f5e89dd40a064f4a6bc84ed3ce
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Thu Oct 17 08:25:55 2024 +0200
+
+    [cpp.subst] Fix typo
+
+commit 88b2b8dcbd145782cfab61e6dad9296c9294593d
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed Oct 16 22:58:07 2024 +0200
+
+    [exec.domain.default] Add missing \pnum
+
+commit 8698ea48e40acc2e18630e799bbb23c41b9344e6
+Author: James Touton <bekenn@gmail.com>
+Date:   Mon Sep 16 21:47:30 2024 -0700
+
+    [over.match.best.general] Minor formatting fixes
+
+commit 7ad39cbf374764a4e232f967e01541419230fedc
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Thu Oct 17 11:16:28 2024 -0400
+
+    [lex.comment] Move the subclause earlier, to where it better fits
+
+    Comments should fit betweem character sets (to define the basic source
+    character set) and preprocessor tokens, that must already understand
+    comments in order to treat them as whitespace.
+
+commit 7f7170cc9b96e9cc76bc0b765837978856936ab1
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Sat Oct 5 16:21:15 2024 -0400
+
+    [depr] Reorder clauses by origin of deprecation
+
+    Reorders the deprecated features annex to follow the order
+    of the main clauses that the deprecates feature refers to.
+    Where multiple clauses are references, use the one named by
+    the [depr.XXX] stable label.
+
+commit cd21b72788d9066f79f31fb6c4516481dfbb4925
+Author: Hewill Kang <hewillk@gmail.com>
+Date:   Fri Oct 18 03:55:20 2024 +0800
+
+    [range.concat.iterator] Remove redundant \expos comments (#6942)
+
+commit 801fb2c0aaf6693a06a9a9e38871bae9536dc194
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Thu Oct 17 17:05:47 2024 -0400
+
+    [lex] Reorder subclauses to better follow phases of translation
+
+    This PR purely moves existing words around, and does not create any new content.
+
+    The proposed subclause ordering is now:
+
+    * 5 Lexical convensions
+      - 5.1 Separate translation
+      - 5.2 Phases of translation
+      - 5.3 Characters
+        - 5.3.1 Character sets
+        - 5.3.2 Universal character names
+      - 5.4 Comments
+      - 5.5 Preprocessing tokens
+      - 5.6 Header names
+      - 5.7 Preprocessing numbers
+      - 5.8 Operators and punctuators
+      - 5.9 Alternative tokens
+      - 5.10 Tokens
+      - 5.11 Identifiers
+      - 5.12 Keywords
+      - 5.13 Literals
+        - 5.13.1 Kinds of literals
+        - 5.13.2 ...
+
+commit 49113a4a577b8d6aed7e5321f0c1fe68d0bd6480
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Oct 18 08:28:28 2024 +0200
+
+    [library.general] Adjust library overview for recent clause restructuring
+
+commit a470ff890be232b9e2a15e44c406ef72c7d816c2
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sat Oct 19 11:31:59 2024 +0200
+
+    [lex.pptoken] Fix indefinitive article for consistency (#7324)
+
+commit 92594a81f021e76dce6acf7ea5d8176350a1e3fb
+Author: Eelis van der Weegen <eelis@eelis.net>
+Date:   Wed Mar 13 21:04:43 2019 +0100
+
+    [temp.deduct.call] Include surrounding code in math formula
+
+commit 0451d08aefd5318254d7d204ad45700aa4d5a2e7
+Author: A. Jiang <de34@live.cn>
+Date:   Mon Oct 21 19:45:10 2024 +0800
+
+    [specialized.algorithms.general] Restore the note for potentially-overlapping objects and undefined behavior (#7326)
+
+    The original note was incorrect and removed (see #6157). But it turns out
+    that _some_ note is still helpful. This PR tries to find the right way to
+    describe storage reusing and potential subsequent undefined behavior.
+
+commit f6b7ef3f1c6e483d97ad5a4f86b3efed38b74c99
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Sat Oct 19 11:41:35 2024 -0400
+
+    [lex.phases] Add crossreferences from phases 3 and 4
+
+    The phases of translation use forward references to the rest
+    of the standard well, but phases 3 and 4 almost entirely lack
+    such crossreferences, despite doing significant work in the
+    process of translating a file.
+
+commit a69507a54e67ae91424d9c621a9cb57ef3ba1512
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Oct 21 17:48:09 2024 +0200
+
+    [locale.codecvt.virtuals] Fix garbled sentence
+
+commit e0576ed2411f36b0ba648afbf6953a0c72c9effb
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Mon Oct 21 13:09:51 2024 -0400
+
+    [compliance] Sort the freestanding headers after clause reorganization
+
+commit b0135f256e40d45faf1d1ac2aaa3abbda36a17c3
+Author: timsong-cpp <rs2740@gmail.com>
+Date:   Tue Oct 22 02:14:47 2024 -0500
+
+    [exec.awaitables] Add missing word (#7340)
+
+commit eb9872aedc581e82e804c0fe8ca7d478ba066b17
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Tue Oct 22 12:09:22 2024 +0200
+
+    [func.wrap.func.con] Fix ill-formed postcondition (#7341)
+
+commit ced2c3866cb3d410c812fa3c359058d185aec329
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Oct 23 13:47:18 2024 -0400
+
+    [allocator.requirements.general] Remove redundant template syntax (#5872)
+
+commit e70d9d6b901457cae9f4f596393f4bf7cee4591a
+Author: Eisenwave <me@eisenwave.net>
+Date:   Mon Oct 21 20:29:10 2024 +0200
+
+    [intro.races] Clarify conflicts for the case where no bits are changed
+
+commit 6ba0dc9b2bf4c3cebc51154e4d543eafb41a8064
+Author: Eisenwave <me@eisenwave.net>
+Date:   Sun Aug 20 00:52:57 2023 +0200
+
+    [intro.memory] remove stray definitions
+
+commit 9dc7b3f30d2971ccb3bb38483a7cdb62065a2c3c
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Oct 22 17:12:25 2024 -0400
+
+    [basic.stc.inherit] Dissolve paragraph into [...general]
+
+    The whole subclause [basic.stc.inherit] is a single sentence that
+    belongs adjacent to the material in [basic.std.general] that
+    specifies how entities acquire a storage duration, wheras all the
+    remaining subclauses below [basic.stc] describe specific storage
+    durations.  Folding that sentence directly into the general clause
+    is even clearer.
+
+commit d5174d561b61304118cdf1042c5697ec6083c181
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Thu Oct 24 09:03:57 2024 +0200
+
+    [basic.link] Add commas between coordinate subclauses (#7342)
+
+commit 8ab0745b6099fd56288763e57ca47dee099db7cb
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Oct 25 10:53:22 2024 +0200
+
+    [bit.cast] change "behaviour" to "behavior" (#7353)
+
+commit 95d491ed6ca7817423855be4f90b61094a1b4312
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sat Oct 26 15:52:55 2024 +0200
+
+    [associative.reqmts.general] Fix punctuation (#7354)
+
+commit 3eb8c47d8f2fe050e221b5d4c36189d965273b37
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Sat Oct 26 16:00:12 2024 +0200
+
+    [basic.compound] Add comma to run-on sentence (#7348)
+
+commit 84af20dcd1976a8982d4418756d1ec9728306580
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sun Oct 27 13:27:34 2024 +0100
+
+    [mdspan.layout.left.cons] Remove duplicate "Effects:" (#7355)
+
+commit ac5b25027266917de3fbb220fc9ecfa4470672f9
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Sun Oct 27 22:46:10 2024 +0100
+
+    [expr.prim.lambda.capture, expr.const, ostream.formatted.print] Reword "automatic variable" (#7358)
+
+commit 324f56439e951773e6ce7437e703fb3aafd5a90c
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Mon Oct 28 07:42:45 2024 -0400
+
+    [lex.pptoken] Reorder paragraphs to define terms before they are used (#7346)
+
+    First move p1 below p2, so that we do not refer to preprocessing tokens before they are defined.
+    Then move p4 up, as it is splitting some unrelated examples, neither of which use its contents.
+
+commit bf43925ff0d9e80997918e98989892b4c7bf15f7
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Oct 29 11:52:02 2024 +0100
+
+    [mdspan.layout.left.cons] Fix typo (#7360)
+
+commit a42d1246936f6376acf6188c1b2053886cdaf3c2
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Sat Nov 2 14:38:54 2024 +0100
+
+    [lib.types.movedfrom] Add cross-reference to [defns.valid] (#7365)
+
+commit 6bfbb59e48b6bde05a78d257cbb943acdb2b6781
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Fri Apr 7 17:09:40 2023 +0800
+
+    [format.string.std] Replace "Derived Extracted Property" with simply "property"
+
+commit aa53618e39f16a6fbf147a8ac2d95a33cb8c5cbc
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Fri Aug 9 17:39:07 2024 +0800
+
+    [lex.name] Strike "Derived Core Properties"
+
+commit cb15975d133869eb18a8b7878343a990e63415e2
+Author: Ilya Burylov <burylov@gmail.com>
+Date:   Wed Nov 6 01:44:54 2024 -0800
+
+    [linalg.helpers.mandates] Fix typos (#7372)
+
+commit fcf95f0f1cb3ae11274f1c3477447aadb76b54ca
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Wed Nov 6 13:27:56 2024 +0100
+
+    [exec.opstate.general] Fix typo (#7370)
+
+commit efa0bec63a2718967f7033217a757d536eba3c18
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed Nov 6 12:55:52 2024 +0000
+
+    [linalg.reqs.val] Fix use of \defnadjx for value types (#7374)
+
+commit 693835ad625acfdf2d610240b99d6d8fecdb8a6a
+Author: Casey Carter <Casey@Carter.net>
+Date:   Sat Nov 16 06:21:27 2024 -0800
+
+    [fs.op.remove] Clarify "Returns" element (#7387)
+
+    To avoid confusion as in microsoft/STL#5088.
+
+commit 1788b3fcd8f3dbe7b31e6bbfbb968ad43d7ecec3
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Sun Nov 17 20:05:57 2024 +0000
+
+    [over.ics.ref] Fix formatting of 'cv T' (#7389)
+
+commit 16df53c4ab9a17942f5bf994031c98105959a5d5
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Mon Nov 18 17:37:02 2024 +0000
+
+    [defns.regex.primary.equivalence.class] Hyphenate 'locale-specific' (#7395)
+
+commit 4f0facdcd57b922510212ddf44ef39f46dcbe44d
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Mon Nov 18 17:38:09 2024 +0000
+
+    [temp.param] Fix typos (#7394)
+
+commit 99deb7022614be47cfcce4f003d8eb57c02b6926
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Tue Nov 19 05:21:45 2024 +0000
+
+    [over.ics.ref] Capitalize 'Exact Match' (#7392)
+
+commit fb8036b6dfe5ce4a99cd85fddac3f115a7fd96af
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Tue Nov 19 05:25:41 2024 +0000
+
+    [class] Avoid hyphenation for 'multidimensional' (#7391)
+
+commit 3f41cf86547b77854abddde7dcaddf2ff00405bf
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Tue Nov 19 05:26:53 2024 +0000
+
+    [lex.phases] Move cross-reference to the first use of the referenced term (#7393)
+
+commit a05b963e9fe12a8589502b4fbc951c119ae1b3b2
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Jul 30 16:51:21 2024 -0400
+
+    [basic.life] Move definition of before and after from bottom to top of subclause
+
+    The last paragraph of this subclause changes the definition of English words
+    used throughout the preceding paragraphs.  While it might be preferable
+    to replace all such usage with the new definitions, that would be a Core issue,
+    see paragraph 6 for an example of awkward usage.  Hence, we move the
+    redefinition to the start of the subclause so we know how to read this text
+    from the start.
+
+commit 2981bd94f25ea2199fd6b8af7aa76e03cf427697
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Sat Oct 19 08:31:08 2024 -0400
+
+    [basic.align] Move the Alignment subclause adjacent to "Object model"
+
+    Alignment puts additional restrictions on object placement.
+
+commit eac0893a9a90a5704deef6db3deecae026f04271
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Oct 2 14:59:41 2024 -0400
+
+    [except.terminate] Better describe the  function
+
+    While 'std:terminate' was originally conceived as the way to
+    report failures in the exception handling machinery, it has
+    evolved to become a more general tool for reporting unrecoverable
+    failures in the C++ runtime.  This rewording attempts to address
+    that evolving design, and in doing so addresses the outstanding
+    %FIXME% that the current text is not adequately descriptive in
+    the first place.
+
+commit f4c4c7cdfb7fba0a6ffbf8e55f2ea6debdf13e87
+Author: xmh0511 <970252187@qq.com>
+Date:   Wed Nov 20 08:17:02 2024 +0800
+
+    [dcl.link] Change "objects" to "entities"
+
+    "Entities" is more appropriate since it includes functions.
+
+commit 38461e17588aff3c6851de6ffc7f3e89418e0e65
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Nov 7 18:50:10 2024 +0800
+
+    [reverse.iter.cons] Removed redundant wording
+
+commit 8caa49a8266d7ef6b4ef3132588d154de07bbabd
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Mar 1 20:49:37 2024 +0100
+
+    [rand.req.seedseq] Remove 'compile-time' complexity for typedefs
+
+commit e2ddc7ab689bdaf91d2b2aa6424cef2510d3677a
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Mar 1 20:50:27 2024 +0100
+
+    [rand.req.dist] Remove 'compile-time' complexity for typedefs
+
+commit c9155b214a51d069cf4a575f10af2b4c4caca5d7
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Mar 1 20:52:39 2024 +0100
+
+    [char.traits.require] Remove 'compile-time' complexity for typedefs
+
+commit 2cd11c5503e78251c0c0fb4147e2d8ccb0947727
+Author: Vlad Serebrennikov <serebrennikov.vladislav@gmail.com>
+Date:   Tue Oct 8 15:30:13 2024 +0400
+
+    [temp.pre] Fix note about uniqueness of a template name in a scope
+
+commit 2edf50afeec8cf200504718646b2b12492dac8ec
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Mon Oct 21 08:33:19 2024 -0400
+
+    [lex.header] Modernize text around header names
+
+    The footnote better belongs in the main text as a regular note.
+    To make the notes flow consistently, switch the order of the
+    note and normative text in the first paragraph to lead with the
+    normative text.
+
+commit 4a5d988a24f6c9737ca076e790b05e22ba169a7a
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Nov 22 12:55:43 2024 +0100
+
+    [refwrap.invoke] Place period at end (#7402)
+
+commit aed97568c63ad5c3c200eff34799413f3ad842f4
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Sat Nov 23 07:53:16 2024 +0100
+
+    [lex.ccon, except.spec] Remove extraneous trailing linebreaks (#7403)
+
+commit 219b959258b6314a3c96bee86b8a18b0f4a7c37e
+Author: mrussoLuxoft <117848841+mrussoLuxoft@users.noreply.github.com>
+Date:   Sat Nov 30 19:36:56 2024 +0100
+
+    [dcl.spec.auto.general] Clarify sentence structure by adding bullets (#7450)
+
+commit 861071a824419b955c4efb2d07980e78c9fc62c7
+Author: Daniel Krügler <daniel.kruegler@gmail.com>
+Date:   Wed Dec 4 15:05:03 2024 +0100
+
+    [iterator.requirements.general] Revert `indirectly_writable` to "writable" definition (#7471)
+
+    This fixes a misapplication of the 2019 Belfast meeting LWG motion 9 (P1878R1), which erroneously replaced the "writable" definition by the `indirectly_writable` concept.
+
+commit c530fd8e0f80029e88b0977bebbf70252d38795e
+Author: Hewill Kang <hewillk@gmail.com>
+Date:   Fri Dec 6 21:52:45 2024 +0800
+
+    [text.encoding.overview] Add cross-reference text_encoding​::​aliases_view (#7476)
+
+commit 10668dceb8186d7990ff4966a6808bb20ba3eed7
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Thu Dec 12 18:47:14 2024 +0000
+
+    [vector.overview,vector.bool.pspc] Move`at() const` to after `at()` (#7484)
+
+    This is consistent with the ordering for operator[].
+
+commit 0b1256638ebf4f1c611c3ca6182bad69be4837ce
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Mon Dec 16 19:53:51 2024 +0100
+
+    [unique.ptr.single.general] Fix typo
+
+commit 76465d7e42f56f763901e3f6a79ae6d77162a510
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Mon Dec 16 12:17:46 2024 +0100
+
+    [expr.type] Fix typo
+
+commit c7fbd5974f4b5e8881d1dc3e8fdf0b59ecba3bab
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Sun Dec 8 07:34:44 2024 +0800
+
+    [locale.ctype.virtuals] Fix a decade-old typo
+
+commit f9c835be8299556ae5943dbb340b4929a6100b15
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Dec 6 16:51:49 2024 +0100
+
+    [except.spec] Remove misleading restriction in list of examples
+
+commit e99e78d67b631fbb328770fbcd4882e683360cb1
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Dec 6 10:57:01 2024 +0100
+
+    [basic.pre,basic.lookup.general] Cleanup definition of term 'name lookup'
+
+commit 57ba5a5f4095ec3df6292cfdc371f554e8b684ef
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Dec 17 12:25:26 2024 -0500
+
+    [lex.phases] Reorder the first two sentences of phase 7 (#7432)
+
+    Currently, the first sentence refers to "tokens" that do not exist until after the second sentence.
+
+commit 55a58f9206e41a831c664747dbacebd25c01b034
+Author: Jan Schultke <me@eisenwave.net>
+Date:   Tue Dec 17 19:34:54 2024 +0100
+
+    [class.conv.ctor] Turn last paragraph into a note (#6505)
+
+commit 3443cd8af21845e5a4fda6246c4c1bbc74cd007b
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Dec 17 19:18:25 2024 +0100
+
+    [exec.envs] Fix typo
+
+commit 14199aed5adb4baaef28245b4de88e7ffe73a365
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Dec 17 20:02:55 2024 +0100
+
+    [atomics.ref.int, atomics.ref.float] Minor \tcode fixes (#7499)
+
+commit daae8f9a9b959c099e99f248324af95bbaf11779
+Author: A. Jiang <de34@live.cn>
+Date:   Wed Dec 18 03:09:10 2024 +0800
+
+    [flat.{map,multimap,set,multiset}] Exposition-only formatting (#6404)
+
+commit 7cbd07c13063b9730d51385198e13bb036d40377
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Mon Dec 16 11:08:10 2024 +0100
+
+    [depr.meta.types] Remove superfluous period
+
+commit 7fe908fa11ad69138975bfec2cf376c66a536d08
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Dec 17 14:13:02 2024 -0500
+
+    [cpp] Distinguish "preprocessing token" from "token" (#7482)
+
+commit 9c9d19f6aef145cf2c074dcdd343e7a2446417a9
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Dec 6 17:37:05 2024 +0000
+
+    [sequence.reqmts] Remove unnecessary qualification of which new element
+
+    There is only one new element, and this avoids having to decide whether it should say args....
+
+ + diff --git a/papers/n5002.md b/papers/n5002.md new file mode 100644 index 0000000000..f5c5e576b1 --- /dev/null +++ b/papers/n5002.md @@ -0,0 +1,697 @@ +# N5002 Editors' Report -- Programming Languages -- C++ + +Date: 2024-12-17 + +Thomas Köppe (editor, Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor, Bright Side Computing, LLC) +Richard Smith (co-editor, Google Inc) + +Email: `cxxeditor@gmail.com` + +## Acknowledgements + +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. +Special thanks to Andreas Krug for many timely editorial fixes. + +## New papers + + * [N5001](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n5001.pdf) is the + current working draft for C++26. It replaces + [N4993](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4993.pdf). + * N5002 is this Editors' Report. + + +## Motions incorporated into working draft + +### Notes on motions + +CWG Poll 9 was retracted. + +Two LWG Polls, Poll 5 (P0472R2) and Poll 17 (P3019R11) have not been applied and +are being sent back to WG21 for clarification. We expect to see revisions to be +approved at the next meeting: + +* LWG Poll 5 accidentally polled for the obsolete revision P0472R2 instead of the + intended P0472R3. It is sent back due to unclear intentions, with a request for + WG21 to clarify, and the expectation that R3 will be approved. + +* LWG Poll 17 caused technical discussion after the meeting, in which some + oversights were observed. The paper authors and the LWG chair agreed that + further LWG review would be in everybody's best interest. The poll is sent back + due to unclear specification, with a request for WG21 to produce a revision, + which we expect to be approved at the next meeting. + +In CWG Poll 1, issue CWG1965 contains no wording changes since it is subsumed by CWG2879. + +### Core working group polls +CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues in +[P3524R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3524r0.html) +(Core Language Working Group "ready" Issues for the November, 2024 meeting) to the C++ Working Paper. + +CWG Poll 2. Apply the changes in +[P3340R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3340r0.pdf) +(A Consistent Grammar for Sequences) to the C++ Working Paper. + +CWG Poll 3. Apply the changes in +[P2686R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2686r5.pdf) +(constexpr structured bindings and references to constexpr variables) to the C++ Working Paper. + +CWG Poll 4. Apply the changes in +[P3068R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r6.html) +(Allowing exception throwing in constant-evaluation) to the C++ Working Paper. + +CWG Poll 5. Apply the changes in +[P3247R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3247r2.html) +(Deprecate the notion of trivial types) to the C++ Working Paper. + +CWG Poll 6. Apply the changes in +[P2865R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2865r6.pdf) +(Remove Deprecated Array Comparisons from C++26) to the C++ Working Paper. + +CWG Poll 7. Apply the changes in +[P1061R10](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1061r10.html) +(Structured Bindings can introduce a Pack) to the C++ Working Paper. + +CWG Poll 8. Apply the changes in +[P3176R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3176r1.html) +(The Oxford variadic comma) to the C++ Working Paper. + +CWG Poll 9 was retracted. + +### Library working group polls + +LWG Poll 1. Apply the changes for all Ready and Tentatively Ready issues in +[P3504R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3504r0.html) +(C++ Standard Library Ready Issues to be moved in Wrocław, Nov. 2024) to the C++ working paper. + +LWG Poll 2. Apply the changes in +[P3136R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3136r1.html) +(Retiring niebloids) to the C++ working paper. + +LWG Poll 3. Apply the changes in +[P3138R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3138r5.html) +(`views::cache_latest`) to the C++ working paper. + +LWG Poll 4. Apply the changes in +[P3379R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3379r0.html) +(Constrain `std::expected` equality operators) to the C++ working paper. + +LWG Poll 5 was sent back (see above). + +LWG Poll 6. Apply the changes in +[P2862R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2862r1.html) +(`text_encoding::name()` should never return null values) to the C++ working paper. + +LWG Poll 7. Apply the changes in +[P2897R7](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2897r7.html) +(`aligned_accessor`: An `mdspan` accessor expressing pointer over-alignment) to the C++ working paper. + +LWG Poll 8. Apply the changes in +[P3355R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3355r1.html) +(Fix `submdspan` for C++26) to the C++ working paper. + +LWG Poll 9. Apply the changes in +[P3222R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3222r0.html) +(Fix C++26 by adding transposed special cases for P2642 layouts) to the C++ working paper. + +LWG Poll 10. Apply the changes in +[P3050R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3050r2.html) +(Fix C++26 by optimizing `linalg::conjugated` for noncomplex value types) to the C++ working paper. + +LWG Poll 11. Apply the changes in +[P3396R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3396r1.html) +(`std::execution` wording fixes) to the C++ working paper. + +LWG Poll 12. Apply the changes in +[P2835R7](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2835r7.html) +(Expose `std::atomic_ref`'s object address) to the C++ working paper. + +LWG Poll 13. Apply the changes in +[P3323R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3323r1.html) +(cv-qualified types in `atomic` and `atomic_ref`) to the C++ working paper. + +LWG Poll 14. Apply the changes in +[P3508R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3508r0.html) +(Wording for "constexpr for specialized memory algorithms") and +[P3369R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3369r0.html) +(`constexpr` for `uninitialized_default_construct`) to the C++ working paper. + +LWG Poll 15. Apply the changes in +[P3370R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3370r1.html) +(Add new library headers from C23) to the C++ working paper. + +LWG Poll 16. Apply the changes in +[P3309R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3309r3.html) +(constexpr `atomic` and `atomic_ref`) to the C++ working paper. + +LWG Poll 17 was sent back (see above). + +LWG Poll 18. Apply the changes in +[P1928R15](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1928r15.pdf) +(`std::simd` — merge data-parallel types from the Parallelism TS 2) to the C++ working paper. + +LWG Poll 19. Apply the changes in +[P3325R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3325r5.html) +(A Utility for Creating Execution Environments) to the C++ working paper. + +## Editorial changes + +### Major editorial changes + +There have not been any major editorial changes. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N4993 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/n4993...n5001). + + commit e9604bcd3d8325860a4db9d02c4f90d0ae70162e + Author: Thomas Köppe + Date: Wed Oct 16 21:12:40 2024 +0100 + + [depr.format.syn] Fix header reference + + commit 0b296da823e7af4a987a0a870ae299420b9ae502 + Author: Thomas Köppe + Date: Thu Oct 17 00:39:04 2024 +0100 + + [{localization,re}.general] Change "This Clause" to "Subclause". + + These subclauses are no longer top-level clauses. + + commit 629e10e2f4177dd24d513be71f2203de325a7e8a + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Thu Oct 17 08:57:39 2024 +0200 + + [inplace.vector.overview] Add missing ',' in comment + + commit 726e07a3a99a87f5e89dd40a064f4a6bc84ed3ce + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Thu Oct 17 08:25:55 2024 +0200 + + [cpp.subst] Fix typo + + commit 88b2b8dcbd145782cfab61e6dad9296c9294593d + Author: Jens Maurer + Date: Wed Oct 16 22:58:07 2024 +0200 + + [exec.domain.default] Add missing \pnum + + commit 8698ea48e40acc2e18630e799bbb23c41b9344e6 + Author: James Touton + Date: Mon Sep 16 21:47:30 2024 -0700 + + [over.match.best.general] Minor formatting fixes + + commit 7ad39cbf374764a4e232f967e01541419230fedc + Author: Alisdair Meredith + Date: Thu Oct 17 11:16:28 2024 -0400 + + [lex.comment] Move the subclause earlier, to where it better fits + + Comments should fit betweem character sets (to define the basic source + character set) and preprocessor tokens, that must already understand + comments in order to treat them as whitespace. + + commit 7f7170cc9b96e9cc76bc0b765837978856936ab1 + Author: Alisdair Meredith + Date: Sat Oct 5 16:21:15 2024 -0400 + + [depr] Reorder clauses by origin of deprecation + + Reorders the deprecated features annex to follow the order + of the main clauses that the deprecates feature refers to. + Where multiple clauses are references, use the one named by + the [depr.XXX] stable label. + + commit cd21b72788d9066f79f31fb6c4516481dfbb4925 + Author: Hewill Kang + Date: Fri Oct 18 03:55:20 2024 +0800 + + [range.concat.iterator] Remove redundant \expos comments (#6942) + + commit 801fb2c0aaf6693a06a9a9e38871bae9536dc194 + Author: Alisdair Meredith + Date: Thu Oct 17 17:05:47 2024 -0400 + + [lex] Reorder subclauses to better follow phases of translation + + This PR purely moves existing words around, and does not create any new content. + + The proposed subclause ordering is now: + + * 5 Lexical convensions + - 5.1 Separate translation + - 5.2 Phases of translation + - 5.3 Characters + - 5.3.1 Character sets + - 5.3.2 Universal character names + - 5.4 Comments + - 5.5 Preprocessing tokens + - 5.6 Header names + - 5.7 Preprocessing numbers + - 5.8 Operators and punctuators + - 5.9 Alternative tokens + - 5.10 Tokens + - 5.11 Identifiers + - 5.12 Keywords + - 5.13 Literals + - 5.13.1 Kinds of literals + - 5.13.2 ... + + commit 49113a4a577b8d6aed7e5321f0c1fe68d0bd6480 + Author: Jens Maurer + Date: Fri Oct 18 08:28:28 2024 +0200 + + [library.general] Adjust library overview for recent clause restructuring + + commit a470ff890be232b9e2a15e44c406ef72c7d816c2 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sat Oct 19 11:31:59 2024 +0200 + + [lex.pptoken] Fix indefinitive article for consistency (#7324) + + commit 92594a81f021e76dce6acf7ea5d8176350a1e3fb + Author: Eelis van der Weegen + Date: Wed Mar 13 21:04:43 2019 +0100 + + [temp.deduct.call] Include surrounding code in math formula + + commit 0451d08aefd5318254d7d204ad45700aa4d5a2e7 + Author: A. Jiang + Date: Mon Oct 21 19:45:10 2024 +0800 + + [specialized.algorithms.general] Restore the note for potentially-overlapping objects and undefined behavior (#7326) + + The original note was incorrect and removed (see #6157). But it turns out + that _some_ note is still helpful. This PR tries to find the right way to + describe storage reusing and potential subsequent undefined behavior. + + commit f6b7ef3f1c6e483d97ad5a4f86b3efed38b74c99 + Author: Alisdair Meredith + Date: Sat Oct 19 11:41:35 2024 -0400 + + [lex.phases] Add crossreferences from phases 3 and 4 + + The phases of translation use forward references to the rest + of the standard well, but phases 3 and 4 almost entirely lack + such crossreferences, despite doing significant work in the + process of translating a file. + + commit a69507a54e67ae91424d9c621a9cb57ef3ba1512 + Author: Jens Maurer + Date: Mon Oct 21 17:48:09 2024 +0200 + + [locale.codecvt.virtuals] Fix garbled sentence + + commit e0576ed2411f36b0ba648afbf6953a0c72c9effb + Author: Alisdair Meredith + Date: Mon Oct 21 13:09:51 2024 -0400 + + [compliance] Sort the freestanding headers after clause reorganization + + commit b0135f256e40d45faf1d1ac2aaa3abbda36a17c3 + Author: timsong-cpp + Date: Tue Oct 22 02:14:47 2024 -0500 + + [exec.awaitables] Add missing word (#7340) + + commit eb9872aedc581e82e804c0fe8ca7d478ba066b17 + Author: Jan Schultke + Date: Tue Oct 22 12:09:22 2024 +0200 + + [func.wrap.func.con] Fix ill-formed postcondition (#7341) + + commit ced2c3866cb3d410c812fa3c359058d185aec329 + Author: Alisdair Meredith + Date: Wed Oct 23 13:47:18 2024 -0400 + + [allocator.requirements.general] Remove redundant template syntax (#5872) + + commit e70d9d6b901457cae9f4f596393f4bf7cee4591a + Author: Eisenwave + Date: Mon Oct 21 20:29:10 2024 +0200 + + [intro.races] Clarify conflicts for the case where no bits are changed + + commit 6ba0dc9b2bf4c3cebc51154e4d543eafb41a8064 + Author: Eisenwave + Date: Sun Aug 20 00:52:57 2023 +0200 + + [intro.memory] remove stray definitions + + commit 9dc7b3f30d2971ccb3bb38483a7cdb62065a2c3c + Author: Alisdair Meredith + Date: Tue Oct 22 17:12:25 2024 -0400 + + [basic.stc.inherit] Dissolve paragraph into [...general] + + The whole subclause [basic.stc.inherit] is a single sentence that + belongs adjacent to the material in [basic.std.general] that + specifies how entities acquire a storage duration, wheras all the + remaining subclauses below [basic.stc] describe specific storage + durations. Folding that sentence directly into the general clause + is even clearer. + + commit d5174d561b61304118cdf1042c5697ec6083c181 + Author: Jan Schultke + Date: Thu Oct 24 09:03:57 2024 +0200 + + [basic.link] Add commas between coordinate subclauses (#7342) + + commit 8ab0745b6099fd56288763e57ca47dee099db7cb + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Oct 25 10:53:22 2024 +0200 + + [bit.cast] change "behaviour" to "behavior" (#7353) + + commit 95d491ed6ca7817423855be4f90b61094a1b4312 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sat Oct 26 15:52:55 2024 +0200 + + [associative.reqmts.general] Fix punctuation (#7354) + + commit 3eb8c47d8f2fe050e221b5d4c36189d965273b37 + Author: Jan Schultke + Date: Sat Oct 26 16:00:12 2024 +0200 + + [basic.compound] Add comma to run-on sentence (#7348) + + commit 84af20dcd1976a8982d4418756d1ec9728306580 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sun Oct 27 13:27:34 2024 +0100 + + [mdspan.layout.left.cons] Remove duplicate "Effects:" (#7355) + + commit ac5b25027266917de3fbb220fc9ecfa4470672f9 + Author: Jan Schultke + Date: Sun Oct 27 22:46:10 2024 +0100 + + [expr.prim.lambda.capture, expr.const, ostream.formatted.print] Reword "automatic variable" (#7358) + + commit 324f56439e951773e6ce7437e703fb3aafd5a90c + Author: Alisdair Meredith + Date: Mon Oct 28 07:42:45 2024 -0400 + + [lex.pptoken] Reorder paragraphs to define terms before they are used (#7346) + + First move p1 below p2, so that we do not refer to preprocessing tokens before they are defined. + Then move p4 up, as it is splitting some unrelated examples, neither of which use its contents. + + commit bf43925ff0d9e80997918e98989892b4c7bf15f7 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Oct 29 11:52:02 2024 +0100 + + [mdspan.layout.left.cons] Fix typo (#7360) + + commit a42d1246936f6376acf6188c1b2053886cdaf3c2 + Author: Jan Schultke + Date: Sat Nov 2 14:38:54 2024 +0100 + + [lib.types.movedfrom] Add cross-reference to [defns.valid] (#7365) + + commit 6bfbb59e48b6bde05a78d257cbb943acdb2b6781 + Author: S. B. Tam + Date: Fri Apr 7 17:09:40 2023 +0800 + + [format.string.std] Replace "Derived Extracted Property" with simply "property" + + commit aa53618e39f16a6fbf147a8ac2d95a33cb8c5cbc + Author: S. B. Tam + Date: Fri Aug 9 17:39:07 2024 +0800 + + [lex.name] Strike "Derived Core Properties" + + commit cb15975d133869eb18a8b7878343a990e63415e2 + Author: Ilya Burylov + Date: Wed Nov 6 01:44:54 2024 -0800 + + [linalg.helpers.mandates] Fix typos (#7372) + + commit fcf95f0f1cb3ae11274f1c3477447aadb76b54ca + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Wed Nov 6 13:27:56 2024 +0100 + + [exec.opstate.general] Fix typo (#7370) + + commit efa0bec63a2718967f7033217a757d536eba3c18 + Author: Jonathan Wakely + Date: Wed Nov 6 12:55:52 2024 +0000 + + [linalg.reqs.val] Fix use of \defnadjx for value types (#7374) + + commit 693835ad625acfdf2d610240b99d6d8fecdb8a6a + Author: Casey Carter + Date: Sat Nov 16 06:21:27 2024 -0800 + + [fs.op.remove] Clarify "Returns" element (#7387) + + To avoid confusion as in microsoft/STL#5088. + + commit 1788b3fcd8f3dbe7b31e6bbfbb968ad43d7ecec3 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Sun Nov 17 20:05:57 2024 +0000 + + [over.ics.ref] Fix formatting of 'cv T' (#7389) + + commit 16df53c4ab9a17942f5bf994031c98105959a5d5 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Mon Nov 18 17:37:02 2024 +0000 + + [defns.regex.primary.equivalence.class] Hyphenate 'locale-specific' (#7395) + + commit 4f0facdcd57b922510212ddf44ef39f46dcbe44d + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Mon Nov 18 17:38:09 2024 +0000 + + [temp.param] Fix typos (#7394) + + commit 99deb7022614be47cfcce4f003d8eb57c02b6926 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Tue Nov 19 05:21:45 2024 +0000 + + [over.ics.ref] Capitalize 'Exact Match' (#7392) + + commit fb8036b6dfe5ce4a99cd85fddac3f115a7fd96af + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Tue Nov 19 05:25:41 2024 +0000 + + [class] Avoid hyphenation for 'multidimensional' (#7391) + + commit 3f41cf86547b77854abddde7dcaddf2ff00405bf + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Tue Nov 19 05:26:53 2024 +0000 + + [lex.phases] Move cross-reference to the first use of the referenced term (#7393) + + commit a05b963e9fe12a8589502b4fbc951c119ae1b3b2 + Author: Alisdair Meredith + Date: Tue Jul 30 16:51:21 2024 -0400 + + [basic.life] Move definition of before and after from bottom to top of subclause + + The last paragraph of this subclause changes the definition of English words + used throughout the preceding paragraphs. While it might be preferable + to replace all such usage with the new definitions, that would be a Core issue, + see paragraph 6 for an example of awkward usage. Hence, we move the + redefinition to the start of the subclause so we know how to read this text + from the start. + + commit 2981bd94f25ea2199fd6b8af7aa76e03cf427697 + Author: Alisdair Meredith + Date: Sat Oct 19 08:31:08 2024 -0400 + + [basic.align] Move the Alignment subclause adjacent to "Object model" + + Alignment puts additional restrictions on object placement. + + commit eac0893a9a90a5704deef6db3deecae026f04271 + Author: Alisdair Meredith + Date: Wed Oct 2 14:59:41 2024 -0400 + + [except.terminate] Better describe the function + + While 'std:terminate' was originally conceived as the way to + report failures in the exception handling machinery, it has + evolved to become a more general tool for reporting unrecoverable + failures in the C++ runtime. This rewording attempts to address + that evolving design, and in doing so addresses the outstanding + %FIXME% that the current text is not adequately descriptive in + the first place. + + commit f4c4c7cdfb7fba0a6ffbf8e55f2ea6debdf13e87 + Author: xmh0511 <970252187@qq.com> + Date: Wed Nov 20 08:17:02 2024 +0800 + + [dcl.link] Change "objects" to "entities" + + "Entities" is more appropriate since it includes functions. + + commit 38461e17588aff3c6851de6ffc7f3e89418e0e65 + Author: A. Jiang + Date: Thu Nov 7 18:50:10 2024 +0800 + + [reverse.iter.cons] Removed redundant wording + + commit 8caa49a8266d7ef6b4ef3132588d154de07bbabd + Author: Eisenwave + Date: Fri Mar 1 20:49:37 2024 +0100 + + [rand.req.seedseq] Remove 'compile-time' complexity for typedefs + + commit e2ddc7ab689bdaf91d2b2aa6424cef2510d3677a + Author: Eisenwave + Date: Fri Mar 1 20:50:27 2024 +0100 + + [rand.req.dist] Remove 'compile-time' complexity for typedefs + + commit c9155b214a51d069cf4a575f10af2b4c4caca5d7 + Author: Eisenwave + Date: Fri Mar 1 20:52:39 2024 +0100 + + [char.traits.require] Remove 'compile-time' complexity for typedefs + + commit 2cd11c5503e78251c0c0fb4147e2d8ccb0947727 + Author: Vlad Serebrennikov + Date: Tue Oct 8 15:30:13 2024 +0400 + + [temp.pre] Fix note about uniqueness of a template name in a scope + + commit 2edf50afeec8cf200504718646b2b12492dac8ec + Author: Alisdair Meredith + Date: Mon Oct 21 08:33:19 2024 -0400 + + [lex.header] Modernize text around header names + + The footnote better belongs in the main text as a regular note. + To make the notes flow consistently, switch the order of the + note and normative text in the first paragraph to lead with the + normative text. + + commit 4a5d988a24f6c9737ca076e790b05e22ba169a7a + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Nov 22 12:55:43 2024 +0100 + + [refwrap.invoke] Place period at end (#7402) + + commit aed97568c63ad5c3c200eff34799413f3ad842f4 + Author: Alisdair Meredith + Date: Sat Nov 23 07:53:16 2024 +0100 + + [lex.ccon, except.spec] Remove extraneous trailing linebreaks (#7403) + + commit 219b959258b6314a3c96bee86b8a18b0f4a7c37e + Author: mrussoLuxoft <117848841+mrussoLuxoft@users.noreply.github.com> + Date: Sat Nov 30 19:36:56 2024 +0100 + + [dcl.spec.auto.general] Clarify sentence structure by adding bullets (#7450) + + commit 861071a824419b955c4efb2d07980e78c9fc62c7 + Author: Daniel Krügler + Date: Wed Dec 4 15:05:03 2024 +0100 + + [iterator.requirements.general] Revert `indirectly_writable` to "writable" definition (#7471) + + This fixes a misapplication of the 2019 Belfast meeting LWG motion 9 (P1878R1), which erroneously replaced the "writable" definition by the `indirectly_writable` concept. + + commit c530fd8e0f80029e88b0977bebbf70252d38795e + Author: Hewill Kang + Date: Fri Dec 6 21:52:45 2024 +0800 + + [text.encoding.overview] Add cross-reference text_encoding​::​aliases_view (#7476) + + commit 10668dceb8186d7990ff4966a6808bb20ba3eed7 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Thu Dec 12 18:47:14 2024 +0000 + + [vector.overview,vector.bool.pspc] Move`at() const` to after `at()` (#7484) + + This is consistent with the ordering for operator[]. + + commit 0b1256638ebf4f1c611c3ca6182bad69be4837ce + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Mon Dec 16 19:53:51 2024 +0100 + + [unique.ptr.single.general] Fix typo + + commit 76465d7e42f56f763901e3f6a79ae6d77162a510 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Mon Dec 16 12:17:46 2024 +0100 + + [expr.type] Fix typo + + commit c7fbd5974f4b5e8881d1dc3e8fdf0b59ecba3bab + Author: S. B. Tam + Date: Sun Dec 8 07:34:44 2024 +0800 + + [locale.ctype.virtuals] Fix a decade-old typo + + commit f9c835be8299556ae5943dbb340b4929a6100b15 + Author: Jens Maurer + Date: Fri Dec 6 16:51:49 2024 +0100 + + [except.spec] Remove misleading restriction in list of examples + + commit e99e78d67b631fbb328770fbcd4882e683360cb1 + Author: Jens Maurer + Date: Fri Dec 6 10:57:01 2024 +0100 + + [basic.pre,basic.lookup.general] Cleanup definition of term 'name lookup' + + commit 57ba5a5f4095ec3df6292cfdc371f554e8b684ef + Author: Alisdair Meredith + Date: Tue Dec 17 12:25:26 2024 -0500 + + [lex.phases] Reorder the first two sentences of phase 7 (#7432) + + Currently, the first sentence refers to "tokens" that do not exist until after the second sentence. + + commit 55a58f9206e41a831c664747dbacebd25c01b034 + Author: Jan Schultke + Date: Tue Dec 17 19:34:54 2024 +0100 + + [class.conv.ctor] Turn last paragraph into a note (#6505) + + commit 3443cd8af21845e5a4fda6246c4c1bbc74cd007b + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Dec 17 19:18:25 2024 +0100 + + [exec.envs] Fix typo + + commit 14199aed5adb4baaef28245b4de88e7ffe73a365 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Dec 17 20:02:55 2024 +0100 + + [atomics.ref.int, atomics.ref.float] Minor \tcode fixes (#7499) + + commit daae8f9a9b959c099e99f248324af95bbaf11779 + Author: A. Jiang + Date: Wed Dec 18 03:09:10 2024 +0800 + + [flat.{map,multimap,set,multiset}] Exposition-only formatting (#6404) + + commit 7cbd07c13063b9730d51385198e13bb036d40377 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Mon Dec 16 11:08:10 2024 +0100 + + [depr.meta.types] Remove superfluous period + + commit 7fe908fa11ad69138975bfec2cf376c66a536d08 + Author: Alisdair Meredith + Date: Tue Dec 17 14:13:02 2024 -0500 + + [cpp] Distinguish "preprocessing token" from "token" (#7482) + + commit 9c9d19f6aef145cf2c074dcdd343e7a2446417a9 + Author: Jonathan Wakely + Date: Fri Dec 6 17:37:05 2024 +0000 + + [sequence.reqmts] Remove unnecessary qualification of which new element + + There is only one new element, and this avoids having to decide whether it should say args.... diff --git a/papers/n5009.html b/papers/n5009.html new file mode 100644 index 0000000000..ec21ca1bed --- /dev/null +++ b/papers/n5009.html @@ -0,0 +1,893 @@ + + + + + +N5009 + + +

N5009 Editors’ Report:
Programming Languages — C++

+ +

Date: 2025-03-15

+ +

Thomas Köppe (editor, Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor, Bright Side Computing, LLC)
+Richard Smith (co-editor, Google Inc)

+ +

Email: cxxeditor@gmail.com

+ +

Acknowledgements

+ +

Thanks to all those who have +submitted editorial issues, +to those who have provided pull requests with fixes, +and to everyone who drafted motion applications.

+ +

New papers

+ +
    +
  • N5008 is the +current working draft for C++26. It replaces +N5001.
  • +
  • N5009 is this Editors' Report.
  • +
+ +

Motions incorporated into working draft

+ +

Notes on motions

+ +

LWG Poll 2 was retracted.

+ +

Library issue LWG4189, +adopted by LWG Poll 1 (P3615R0) had the effect of making most of the content of <ranges> +free-standing by default, with the note that "[m]ost future additions to this header should +have no problem being freestanding, so that is the right default." Absent an explicit +opt-out, the new facilities from LWG Poll 14 +(P2846R6), +reserve_hint and approximately_sized_range, are now free-standing as well.

+ +

Core working group polls

+ +

CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues in +P3638R0 +(Core Language Working Group "ready" Issues for the February, 2025 meeting) to the C++ Working Paper.

+ +

CWG Poll 2. Apply the changes in P3542R0 +(Abolish the term "converting constructor") to the C++ Working Paper.

+ +

CWG Poll 3. Apply the changes in P3074R7 +(trivial unions (was std::uninitialized)) to the C++ Working Paper.

+ +

CWG Poll 4. Apply the changes in P1494R5 +(Partial program correctness) to the C++ Working Paper.

+ +

CWG Poll 5. Apply the changes in P2900R14 +(Contracts for C++) to the C++ Working Paper.

+ +

CWG Poll 6. Apply the changes in P3475R2 +(Defang and deprecate memory_order::consume) to the C++ Working Paper.

+ +

CWG Poll 7. Apply the changes in P2841R7 +(Concept and variable-template template-parameters) to the C++ Working Paper.

+ +

CWG Poll 8. Apply the changes in P2786R13 +(Trivial Relocatability For C++26) to the C++ Working Paper.

+ +

CWG Poll 9. Apply the changes in P1967R14 +(#embed - a simple, scannable preprocessor-based resource acquisition method) to the C++ Working Paper.

+ +

Library working group polls

+ +

LWG Poll 1. Apply the changes for all Tentatively Ready issues in +P3615R0 +(C++ Standard Library Ready Issues to be moved in Hagenberg, Feb. 2025) to the C++ working paper.

+ +

LWG Poll 2 was retracted.

+ +

LWG Poll 3. Apply the changes in P3137R3 +(views::to_input) to the C++ working paper.

+ +

LWG Poll 4. Apply the changes in P0472R3 +(Put std::monostate in <utility>) to the C++ working paper.

+ +

LWG Poll 5. Apply the changes in P3349R1 +(Converting contiguous iterators to pointers) to the C++ working paper.

+ +

LWG Poll 6. Apply the changes in P3372R3 +(constexpr containers and adaptors) to the C++ working paper.

+ +

LWG Poll 7. Apply the changes in P3378R2 +(constexpr exception types) to the C++ working paper.

+ +

LWG Poll 8. Apply the changes in P3441R2 +(Rename simd_split to simd_chunk) to the C++ working paper.

+ +

LWG Poll 9. Apply the changes in P3287R3 +(Exploration of namespaces for std::simd) to the C++ working paper.

+ +

LWG Poll 10. Apply the changes in P2976R1 +(Freestanding Library: algorithm, numeric, and random) to the C++ working paper.

+ +

LWG Poll 11. Apply the changes in P3430R3 +(SIMD issues: explicit, unsequenced, identity-element position, and members of disabled SIMD) to the C++ working paper.

+ +

LWG Poll 12. Apply the changes in P2663R7 +(Interleaved complex values support in std::simd) to the C++ working paper.

+ +

LWG Poll 13. Apply the changes in P2933R4 +(Extend <bit> header function with overloads for std::simd) to the C++ working paper.

+ +

LWG Poll 14. Apply the changes in P2846R6 +(reserve_hint: Eagerly reserving memory for not-quite-sized lazy ranges) to the C++ working paper.

+ +

LWG Poll 15. Apply the changes in P3471R4 +(Standard Library Hardening) to the C++ working paper.

+ +

LWG Poll 16. Apply the changes in P0447R28 +(Introduction of std::hive to the standard library) to the C++ working paper.

+ +

LWG Poll 17. Apply the changes in P3019R14 +(indirect and polymorphic: Vocabulary Types for Composite Class Design) to the C++ working paper.

+ +

Editorial changes

+ +

Major editorial changes

+ +

There have not been any major editorial changes.

+ +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N5001 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 f3676cb1550f1501236cc65c1dfa2dec957bbdf2
+Author: Mark Hoemmen <mhoemmen@users.noreply.github.com>
+Date:   Tue Dec 17 14:15:10 2024 -0700
+
+    [linalg.conj.conjugated] Remove inappropriate "expression-equivalent" wording (#7497)
+
+    This phrase appears to be copy-pasted from elsewhere, but is not meaningful here.
+
+commit be0a25c9a2f2c1f498b0ff84a33c28adae41863e
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Dec 17 20:31:14 2024 +0100
+
+    [simd.alg] Fix range syntax
+
+commit a18040f05ff6a27e5c6425005ab1b21515ad952c
+Author: Eisenwave <me@eisenwave.net>
+Date:   Fri Nov 1 08:06:28 2024 +0100
+
+    [basic.compound] Update introduction
+
+commit 0131e015c09eca1901d0bfa46744a6c7ab31b00d
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue Dec 17 21:21:42 2024 +0000
+
+    [linalg.helpers] Rename template parameter for poison pills
+
+    This avoids reusing `T` which is also used for the type of the
+    subexpression E.
+
+    Fixes #7494
+
+commit 04169bac7059322ad8bf32e605a80e57ef30b922
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Dec 17 22:51:01 2024 +0100
+
+    [inplace.vector.overview] Replace residual use of 'trivial type'
+
+commit 9272753d0ecbc1df9d08178793795f06b623a451
+Author: Hewill Kang <hewillk@gmail.com>
+Date:   Tue Nov 19 16:41:00 2024 +0800
+
+    [flat.map.defn, flat.set.defn] Avoid naming the from_range_t tag
+
+commit 85de0af0e0af416f7e73ac096254641c31bf11cc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Dec 17 23:19:21 2024 +0100
+
+    [basic.fundamental] Ensure consistency with [conv.ptr]
+
+commit 561a4d8cde9e434fe206b88489e95b0e5271f469
+Author: Mark Hoemmen <mhoemmen@users.noreply.github.com>
+Date:   Thu Dec 19 14:35:50 2024 -0700
+
+    [bibliography] Fix spelling and formatting (#7507)
+
+    Fix spelling of one author's name.  Add missing commas
+    and extra spaces after a period ending authors' abbreviated
+    first or middle names.
+
+commit 82153790d8904ea82bc57edc8885b02925e85e93
+Author: Mark Hoemmen <mhoemmen@users.noreply.github.com>
+Date:   Thu Dec 19 14:41:02 2024 -0700
+
+    [simd.general, bibliography] Add SIMD acronym explanation and bibliographic reference (#7504)
+
+    To the existing Note at the beginning of [simd.general],
+    add text that unpacks the SIMD acronym and refers to Flynn 1966.
+
+    Add bibliography entry for Flynn 1966, the paper that introduced what
+    later became known as "Flynn's Taxonomy."  This classifies parallel
+    computer hardware as SISD, SIMD, MISD, or MIMD.
+
+commit e1a368bc157f824cee7702e87a2cca1951e60f98
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Thu Dec 19 11:02:38 2024 +0000
+
+    [mdspan.sub] Change to "unit-stride slice for mapping"
+
+    This was the wording requested by LWG and approved in P3355R2, but I
+    mistakenly put P3355R1 in the straw polls.
+
+commit 2d3ac367d8605d7172151726e873daea295a573a
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Dec 20 10:15:46 2024 +0100
+
+    [diff.cpp03.library] Correct \effect to \change
+
+    - Correct \effect to \change.
+    - Add period at end.
+    - Add \tcode for swap.
+
+commit a2429a5944b71e3563dc09730426af43fb4b53e1
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Thu Dec 26 01:37:34 2024 +0000
+
+    [class.expl.init] Fix incorrect note
+
+commit 1411cf56fcb41f9fd000406185f17ef47235d26a
+Author: Bronek Kozicki <brok@incorrekt.com>
+Date:   Wed Jan 1 17:00:14 2025 +0000
+
+    [expected.bad.void] Fix syntax error in bad_expected_access<void> (#7529)
+
+    Introduced by commit 8c997445c176c81a334e77f9344b91abc72b2772
+
+commit a137940ac9c807e3ea809c3ff0b3a863795bf742
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Wed Jan 1 22:18:37 2025 +0100
+
+    [filebuf.members,fs.path.req] Fix indefinite article (#7530)
+
+commit d2b48043fcc219b2a141af39dae2eb85934c0847
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jan 2 10:49:14 2025 +0100
+
+    [expr.const] Properly merge P2686R5
+
+    P2686R5 (applied by commit e220906b71df01f09fe60921e8fac39b80558f78)
+    accidentally reverted a change considering erroneous values made by
+    P2795R5.
+
+commit 22937c04da139226c186973eda2cdb79df640b5b
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Thu Jan 2 15:14:06 2025 +0100
+
+    [format.arg] Fix indefinite article (#7536)
+
+commit 75af9f7f8cd816e1908eb2a3917eb7749c11471a
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Sat Jan 4 02:18:53 2025 +0700
+
+    [tuple.helper] Remove redundant 'public' in base-specifier of struct (#7539)
+
+commit 6ff55d533f72b7222e022513dcb80982f4e887a0
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Dec 30 16:34:49 2024 +0100
+
+    [lex.icon,depr.locale.category] Remove duplicate 'table' in front of table references
+
+commit 70df8aa8f4a30a7d54a604cbe01ebe13f5973043
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Wed Jan 8 13:51:13 2025 +0100
+
+    [linalg.algs.blas2.gemv] Fix singular/plural mismatch (#7546)
+
+commit 0164098f821ae002469c6f23cd03fc66a0a2f7ca
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Thu Jan 9 10:01:36 2025 +0000
+
+    [basic.def.odr] Fix typo and reference the correct subclause
+
+commit 2734ddeb05115f3fddf09c9c15b843083575e9df
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Jan 10 13:13:28 2025 +0100
+
+    [exec.async.ops] Remove stray closing parenthesis (#7555)
+
+commit 77171de904e6008f31717615d5baabf604baeea8
+Author: S. B. Tam <cpplearner@outlook.com>
+Date:   Fri Jan 10 23:05:58 2025 +0800
+
+    [locale.time.put.members] Remove incorrect footnote (#7553)
+
+commit 6ecd1be67c71001db37883ee45b76cc66ef4101f
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Jan 13 22:34:47 2025 +0100
+
+    [exec.getcomplsigs] Add missing LaTeX escaping of braces (#7541)
+
+commit 1b1914ed868b0b29e63d0d1e4b872daf07b50740
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Jan 14 14:31:09 2025 +0100
+
+    [simd.traits] Remove stray closing parenthesis (#7563)
+
+commit 0ac6f9d7e94a70b48457f289bcbeb069a4662c28
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Wed Jan 15 14:10:57 2025 +0100
+
+    [locale.moneypunct.general] Insert period at end (#7564)
+
+commit 96fad4cf7ff48c8a4ae5442580d55008fb56ca43
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Jan 15 10:06:49 2025 -0500
+
+    [inplace.vector.overview] Remove spurious semicolon closing namespace std (#7566)
+
+commit 1c398ffc71845163ca50b712f1edd9e1b2a87772
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Jan 17 17:11:02 2025 +0000
+
+    [type.info] Remove comments explaining deleted members
+
+    The standard is not a tutorial.
+
+commit 569e2a38cf1aa6d185b4c4d1817d9496ebd087e5
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jan 18 09:18:53 2025 +0100
+
+    [exec.snd.expos] Move write-env paragraph into itemdescr (#7571)
+
+commit 93aa7cb89b375280cb2d5f385fb0c5a5874e9243
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sat Jan 18 23:32:20 2025 +0100
+
+    [re.err,re.alg.match,re.tokiter.incr] Add period at end for consistency (#7574)
+
+commit ce5fd62b98d822228f46319f4516e34c492fa257
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Wed Jan 22 16:15:57 2025 +0100
+
+    [string.view.io,string.insert] Add period at end of "Returns" (#7579)
+
+commit 5c4823a05b83a67f7550fdcc1476f8000c29514c
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Jan 23 11:31:05 2025 +0800
+
+    [expr.const] Re-apply CWG2909
+
+commit db563eecdfb63cb24f10afb30f001a0bc6213997
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Jan 15 07:59:51 2025 -0500
+
+    [lex.phases] Update implementation defined text
+
+    Since C++23 we no longer have physical source files, but rather
+    input files.  Update the two implementation-defined references
+    to the mapping from input file to translation character set
+    using the same phrasing so that they provide the same entry
+    in the index of implementation-defined behavior, just as they
+    did in C++20, before getting out of sync when the terminology
+    changed.
+
+commit a39cca2e9c009766da1e205daf5d7bf8cbdccaa3
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Thu Jan 23 07:28:40 2025 -0500
+
+    [linalg.conj.conjugated] Rearrange to match P3050R3 (#7506)
+
+    This was the wording requested by LWG and approved in P3050R3, but I
+    mistakenly put P3050R2 in the straw polls.
+
+commit 6583c4ac9c2d3bbfb7daac0c79c902a30417c50f
+Author: cor3ntin <corentinjabot@gmail.com>
+Date:   Sat Jan 25 14:11:30 2025 +0100
+
+    [std] Use template-parameter and template parameter more consistently (#7460)
+
+    Try to use template-parameter only when we refer to a
+    grammar construct, and to 'template parameter' everywhere else.
+
+    Adopt the same logic to template-argument/template argument.
+
+    This change might not be  exhaustive.
+
+    The aim is to editorially adopt some of the wording changes
+    made in P2841R5 to ease its review in core.
+
+commit 696dcd809ceed3fc10502161963f8ce13505ec1a
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jan 25 21:25:32 2025 +0100
+
+    [format.string.general,format.formatter.spec] Fix unparenthesized cross-references
+
+commit 47cf5a67357543b0d45d0072f42fdd29fa028cca
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Wed Jan 29 09:29:54 2025 +0100
+
+    [alg.rand.generate] Add period at end of "Returns" (#7595)
+
+commit b2b266e7b67eb583c50c34a9eceffe44f72ea2f6
+Author: Ivan Lazarić <ivan.lazaric1@gmail.com>
+Date:   Sat Feb 1 09:56:42 2025 +0100
+
+    [temp.res.general] Fix nesting for \terminal{\opt{...}} (#7599)
+
+commit d51e6bedd991d55b7f7fb7f41e1f08083cfd1b1d
+Author: Eric Niebler <eniebler@boost.org>
+Date:   Mon Feb 3 12:05:48 2025 -0800
+
+    [range.view] Change incorrect uses of "which" to "that" (#7606)
+
+commit 1d49b05d1b48a2daa2a88d854e2367e6648c3cb6
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Mon Feb 3 21:14:45 2025 +0100
+
+    [tuple.assign] Remove incorrect comma at end (#7609)
+
+commit 2e1b856b6187fe9a5c74782948982eefd128ecbf
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Mon Feb 3 16:17:48 2025 -0500
+
+    [diff.cpp.library] Add new C23 headers to list of new headers
+
+commit cae9b2a645d5bb91caffc061325f107605e85a0d
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Tue Feb 4 09:30:49 2025 +0100
+
+    [container.alloc.reqmts,sequence.reqmts] Add period at end (#7614)
+
+commit 003506a2779c519d4929cce75c7adeb1b7a76955
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Jan 1 18:45:19 2025 +0700
+
+    [macros] Add LaTeX macros to index library macros
+
+    The immediate idea is to support using the new macros directly
+    in header synopses when defining each library macro.  This will
+    ensure that no macros are accidentally not indexed.
+
+    A follow-up plan is that this separation of library macros will
+    make it easier to create a separate index of macros, or apply
+    other macro-specific renderings, in the future.  To this end,
+    all indexed uses of a macro, not just those in header files,
+    should be replaced by use of these new macros.  Similarly,
+    these LaTeX macros can be used in-place in regular text to
+    index cross-references where standard library macros are used
+    throughout the standard.
+
+commit d7618b4d20a24b37677b92c2fbd80dcee4565bc3
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Feb 7 09:37:37 2025 +0100
+
+    [diff.lex] Add period at end (#7618)
+
+commit 040ff41df1d0e0e4d31bd6c76f084fbc84239e7f
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Sat Feb 8 07:56:45 2025 +0000
+
+    [fs.op.current.path] Remove note discussing design choices (#7620)
+
+commit dfdc64cbdc842f0f7d2a060440ea907b41ce78e6
+Author: Vlad Serebrennikov <serebrennikov.vladislav@gmail.com>
+Date:   Sun Feb 9 20:12:44 2025 +0400
+
+    [basic.scope.scope] Update the note about special cases (#7594)
+
+commit 8948fd9bd8f799d50fc9cbff34b349b9d59157f1
+Author: André Brand <andre.brand@mailbox.org>
+Date:   Sun Feb 9 17:18:12 2025 +0100
+
+    [temp.mem.enum] Remove instantiation in example [temp.inst] (#7558)
+
+    The example is inconsistent with [temp.inst]p3. Since the implicit instantiation
+    does not contribute to the point of [temp.mem.enum], the inconsistency
+    can be resolved by omitting the instantiation.
+
+commit 0d0ea5582082f85fa707c680634044209c2e343d
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Mon Nov 18 13:47:37 2024 +0000
+
+    [defns.argument] Mention braced-init-list
+
+commit 7566675c778f95ef966c4fea058a895def98e6d1
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Sun Feb 9 11:23:22 2025 -0500
+
+    [lex.phases] Use preprocessing token consistently (#7361)
+
+    Prior to converting preprocessing tokens to tokens in phase 7,
+    all tokens are strictly preprocessing tokens.
+
+commit b9f054b0cba3a36f9c8eff0c190f85996597dc3d
+Author: cor3ntin <corentinjabot@gmail.com>
+Date:   Mon Feb 10 07:47:58 2025 +0100
+
+    [std] Rename "non-type" to "constant" template parameter/argument (#7587)
+
+    Note that not all instances of "non-type" have been mechanically replaced,
+    as [dcl] and [diff] use the term to refer to anything that is not a type
+    in the context of lookup.
+
+commit 45eb50507a1b6477dea6106c3c26654b96feae4a
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Fri Jan 31 14:04:53 2025 -0500
+
+    [cmath.syn] Consolidate std namespaces
+
+    There is no ordering dependency between the two typedefs
+    in namespace std, the macros that follow, and teh next
+    opening of namespace std, so move the two typedefs to
+    avoid repeatedly opening an closing the namespace.
+
+    Note that we could have done this without moving
+    the typedefs as macros are not bound by namespaces,
+    but our convention very sensibly avoids confusing
+    readers by keeping macro definitions outside of
+    namespaces.
+
+commit 5eab5c6b456db2424b04becb791b23dbf4de356a
+Author: Axel Naumann <Axel.Naumann@cern.ch>
+Date:   Mon Jan 27 15:50:24 2025 +0100
+
+    [class.prop] add ref to actual layout spec in [expr.rel]
+
+commit 2f42a31044cc1ec8cf119b0fd595fdcc1d625c59
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Jan 23 11:37:15 2025 +0800
+
+    [util.smartptr.atomic.{shared,weak}] Fix wording for initialization
+
+    By using more conventional "value-initializes".
+
+commit 4e026ec784007b492eb3d904663cfdc4bf905fd3
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue Feb 4 11:09:05 2025 +0000
+
+    [fs.op.funcs] Remove empty parens when referring to functions by name
+
+    As per the Specification Style Guidelines.
+
+    https://github.com/cplusplus/draft/wiki/Specification-Style-Guidelines#describing-function-calls
+
+commit 7f00883b8f65307b7e0df0ad2e55182d699d2804
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Jan 13 22:33:34 2025 +0100
+
+    [xrefdelta] Restore cross-references since C++17
+
+commit 7fbdb79d99338d9aa91f382760ff6e1cb0353c71
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Oct 1 09:20:10 2024 -0400
+
+    [except.uncaught] Tidy the specification for uncaught exceptions
+
+    Several concurrent fixes.  First include the normative wording
+    that 'uncaught_exceptions' returns the number of uncaught
+    exceptions *on the current thread*.  This wording is present
+    in the core language.
+
+    Then move the core wording for when an exception is uncaught
+    directly into the text that talks about caught and uncaught
+    exceptions.  In the process, turn the reference to into a note,
+    so that there is only one normative specification.
+
+    Finally, remove [except.uncaught] as it is now empty.
+
+commit 70abf300ddbb1074cd16e9a5febe7f7c88bdff3d
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Nov 20 02:07:51 2024 +0100
+
+    [except.special.general] Complete the set of clause 17 references
+
+commit 888b0510da303e367f7421ac34607a158ddfc453
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Tue Jan 21 04:31:34 2025 -0500
+
+    [basic.pre] Defragment specification of names and entities
+
+    The current contents of [basic.pre] jump between specifying
+    different things.  This PR moves all the specification of
+    names to the front, followed by the specification of entities.
+
+    There are two main benefits: (1) the specification for when
+    two names are the same is a list of 4 rules that correspond
+    to the 4 things than can form a name --- the connection is
+    much clearer when the paragraphs are adjacent and the list
+    is sorted to the same order; (2) in this form, even though
+    all the words are the same, the reordering and merging of
+    paragraphs a fit on a single page.  The very last paragraph
+    was forced over a page-break in the original layout.
+
+commit 5be40a6b59527e82b13a29722c623635065759bf
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Tue Feb 11 21:42:20 2025 +0100
+
+    [expr.lval] Update cross reference for "invalid pointer value"
+
+commit 83530f54892686c9ba055434d02dfadc00bbb290
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Aug 3 00:54:57 2023 +0800
+
+    [basic.extended.fp] Use "declared" for typedef-names
+
+commit 1542d983b3f690876720d69a44dff2c5574617b3
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Aug 3 01:00:16 2023 +0800
+
+    [expr.{add,alignof,sizeof}] Use "typedef-name", avoid "defined"
+
+commit 152693b46648ea99493aecedbc8051aa2ab7542f
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Wed Feb 12 17:58:51 2025 +0000
+
+    [temp.param, temp.constr.normal] Use \dotsc for a non-code ellipsis (#7397)
+
+commit 930b8f97b0ab7bd9442bd0faf10f7302da5fc89a
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Wed Feb 12 19:22:47 2025 +0100
+
+    [diff.cpp03.library] Fix cross-reference to restriction on macro names
+
+commit 2cfc175a01d2bff1daf084d5c776017c5c049872
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Thu Feb 13 22:28:24 2025 +0000
+
+    [linalg.general] Remove extraneous dot (#7637)
+
+commit 422ded52d1876578f4eeb3bc30d583a193b94f42
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Fri Feb 14 19:13:02 2025 +0100
+
+    [conv.rank] Fix typo
+
+commit 10468bf63eee8926b84b76a10abb2a7d05b43c02
+Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com>
+Date:   Sun Feb 16 12:13:43 2025 +0100
+
+    [map.overview] Fix punctuation (#7677)
+
+commit a103bf3ea67a731189a8f1453d3e9ab88d589eba
+Author: Alisdair Meredith <alisdairm@me.com>
+Date:   Mon Feb 24 07:46:22 2025 -0500
+
+    [xrefdelta] Consolidate restored entries (#7631)
+
+    Several entries in the restored larger delta referred
+    to stable labels that have since moved again, or have been
+    removed.  This commit updates their cross-references
+    accordingly, or marks them as removed if appropriate.
+
+commit 9854e729ba5ade9a41bf047b6a5fe6f4bbe038e0
+Author: Hubert Tong <hstong@ca.ibm.com>
+Date:   Thu Feb 13 17:01:13 2025 -0500
+
+    [basic.types.general] Change ordering to "non-variant non-static"
+
+    The definition of literal type is the only place where "non-static
+    non-variant data member" is used as opposed to "non-variant non-static
+    data member".
+
+    Change to use the canonical ordering.
+
+commit c31b8f4111dfa9dd598220b9c6f8c1cf9d4a9b34
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue Feb 25 09:54:40 2025 +0000
+
+    [support.srcloc.cons] Update xref to [class.mem.general]
+
+    The cross-reference to [class.mem] was referring to a hanging paragraph
+    that was fixed by 2850139be6285ba10a64fb718125a80ca967c631 so we should
+    be referring to [class.mem.general] now.
+
+commit 912e5cab7565be0daa9c0c6d7c178600b3cd38e6
+Author: lprv <100177227+lprv@users.noreply.github.com>
+Date:   Sat Mar 15 20:23:43 2025 +0000
+
+    [functional.{syn,bind.place}] Use \vdots; add missing \placeholder (#7723)
+
+commit 0dda8468be890adf880afddc37e449cbc40607cb
+Author: A. Jiang <de34@live.cn>
+Date:   Sun Mar 16 04:26:10 2025 +0800
+
+    [expr.const] Change "value" to "result object" (of a prvalue) (#6267)
+
+commit 4552a92a01a2d1b032264cd6568a860a5244918b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Nov 7 22:35:21 2021 +0100
+
+    [lex.string] Clarify size of string-literal
+
+commit ec10aaec4e6daac66b7b28426abcc765494194c9
+Author: Hubert Tong <hubert.reinterpretcast@gmail.com>
+Date:   Sat Mar 15 16:41:54 2025 -0400
+
+    [debugging.utility] Clarify wording in notes
+
+    The previous wording in the notes in `breakpoint` and `is_debugger_present`
+    read as statements of fact about the implementation-defined behaviour.
+    The statements are actually ones of intent.
+
+    The specific claim in `breakpoint` that the debugger resumes execution of the program
+    as if the function was not invoked is confusing considering that the debugger may effect
+    side-effects or cause execution to resume from a different evaluation.
+
+    Instead, the idea is that `breakpoint` is not responsible for causing the translation process
+    to make special accomodations for resumption of execution other than in cases
+    where the debugger was strictly used for observation only.
+
+    In `is_debugger_present`, the functionality ascribed to POSIX by the wording
+    ("ptrace") is not present in POSIX. Update to reference the LSB and to use
+    the corresponding terminology ("tracing process").
+
+    The wording implies a preference to return `true` in case it is unknown
+    whether a debugger is present. Add a critical "only" to fix that.
+
+commit 598910dc970bc0bc840ba797983e9bc131cd826e
+Author: A. Jiang <de34@live.cn>
+Date:   Tue Feb 25 07:51:44 2025 +0800
+
+    [ifstream.members] Remove mistakenly added `@`
+
+commit 4b5a0080230ed74d796a3ee909bdde66e2f2b395
+Author: A. Jiang <de34@live.cn>
+Date:   Wed Aug 7 18:45:41 2024 +0800
+
+    [func.wrap.func] Drop Lvalue-Callable
+
+    Replace its usages with `is_invocable_r_v` and remove an unnecessary index.
+
+commit f9847af90413adb0436aae9f6895b4a2e0e173ec
+Author: A. Jiang <de34@live.cn>
+Date:   Mon Feb 17 11:44:11 2025 +0800
+
+    [containers, strings, algorithms, re] Use \range where appropriate
+
+    Currently, there are several cases where `\tcode{[i, j)}` is used for
+    specifying left-closed right-open intervals, where `\range{i}{j}` is proper.
+
+    Co-authored-by: Eelis van der Weegen <eelis@eelis.net>
+
+commit 73699cf37d247a7c1f3a6879197c730a14666b90
+Author: languagelawyer <38548419+languagelawyer@users.noreply.github.com>
+Date:   Fri Feb 26 02:55:52 2021 +0300
+
+    [class.cdtor] Only objects of scalar type can be accessed
+
+ + diff --git a/papers/n5009.md b/papers/n5009.md new file mode 100644 index 0000000000..2caf3f0571 --- /dev/null +++ b/papers/n5009.md @@ -0,0 +1,753 @@ +# N5009 Editors' Report -- Programming Languages -- C++ + +Date: 2025-03-15 + +Thomas Köppe (editor, Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor, Bright Side Computing, LLC) +Richard Smith (co-editor, Google Inc) + +Email: `cxxeditor@gmail.com` + +## Acknowledgements + +Thanks to all those who have +[submitted editorial issues](https://github.com/cplusplus/draft/wiki/How-to-submit-an-editorial-issue), +to those who have provided pull requests with fixes, +and to everyone who drafted motion applications. + +## New papers + + * [N5008](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5008.pdf) is the + current working draft for C++26. It replaces + [N5001](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/n5001.pdf). + * N5009 is this Editors' Report. + +## Motions incorporated into working draft + +### Notes on motions + +LWG Poll 2 was retracted. + +Library issue [LWG4189](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3615r0.html#4189), +adopted by LWG Poll 1 (P3615R0) had the effect of making most of the content of `` +free-standing by default, with the note that "[m]ost future additions to this header should +have no problem being freestanding, so that is the right default." Absent an explicit +opt-out, the new facilities from LWG Poll 14 +([P2846R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2846r6.html)), +`reserve_hint` and `approximately_sized_range`, are now free-standing as well. + +### Core working group polls + +CWG Poll 1. Accept as Defect Reports and apply the proposed resolutions of all issues in +[P3638R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3638r0.html) +(Core Language Working Group "ready" Issues for the February, 2025 meeting) to the C++ Working Paper. + +CWG Poll 2. Apply the changes in [P3542R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3542r0.html) +(Abolish the term "converting constructor") to the C++ Working Paper. + +CWG Poll 3. Apply the changes in [P3074R7](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3074r7.html) +(trivial unions (was `std::uninitialized`)) to the C++ Working Paper. + +CWG Poll 4. Apply the changes in [P1494R5](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1494r5.html) +(Partial program correctness) to the C++ Working Paper. + +CWG Poll 5. Apply the changes in [P2900R14](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2900r14.pdf) +(Contracts for C++) to the C++ Working Paper. + +CWG Poll 6. Apply the changes in [P3475R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3475r2.pdf) +(Defang and deprecate `memory_order::consume`) to the C++ Working Paper. + +CWG Poll 7. Apply the changes in [P2841R7](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2841r7.pdf) +(Concept and variable-template template-parameters) to the C++ Working Paper. + +CWG Poll 8. Apply the changes in [P2786R13](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2786r13.html) +(Trivial Relocatability For C++26) to the C++ Working Paper. + +CWG Poll 9. Apply the changes in [P1967R14](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1967r14.html) +(`#embed` - a simple, scannable preprocessor-based resource acquisition method) to the C++ Working Paper. + +### Library working group polls + +LWG Poll 1. Apply the changes for all Tentatively Ready issues in +[P3615R0](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3615r0.html) +(C++ Standard Library Ready Issues to be moved in Hagenberg, Feb. 2025) to the C++ working paper. + +LWG Poll 2 was retracted. + +LWG Poll 3. Apply the changes in [P3137R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3137r3.html) +(`views::to_input`) to the C++ working paper. + +LWG Poll 4. Apply the changes in [P0472R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0472r3.pdf) +(Put `std::monostate` in ``) to the C++ working paper. + +LWG Poll 5. Apply the changes in [P3349R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3349r1.html) +(Converting contiguous iterators to pointers) to the C++ working paper. + +LWG Poll 6. Apply the changes in [P3372R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3372r3.html) +(constexpr containers and adaptors) to the C++ working paper. + +LWG Poll 7. Apply the changes in [P3378R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3378r2.html) +(constexpr exception types) to the C++ working paper. + +LWG Poll 8. Apply the changes in [P3441R2](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3441r2.html) +(Rename `simd_split` to `simd_chunk`) to the C++ working paper. + +LWG Poll 9. Apply the changes in [P3287R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3287r3.pdf) +(Exploration of namespaces for `std::simd`) to the C++ working paper. + +LWG Poll 10. Apply the changes in [P2976R1](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2976r1.html) +(Freestanding Library: algorithm, numeric, and random) to the C++ working paper. + +LWG Poll 11. Apply the changes in [P3430R3](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3430r3.pdf) +(SIMD issues: explicit, unsequenced, identity-element position, and members of disabled SIMD) to the C++ working paper. + +LWG Poll 12. Apply the changes in [P2663R7](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2663r7.html) +(Interleaved complex values support in `std::simd`) to the C++ working paper. + +LWG Poll 13. Apply the changes in [P2933R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2933r4.html) +(Extend `` header function with overloads for `std::simd`) to the C++ working paper. + +LWG Poll 14. Apply the changes in [P2846R6](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2846r6.pdf) +(`reserve_hint`: Eagerly reserving memory for not-quite-sized lazy ranges) to the C++ working paper. + +LWG Poll 15. Apply the changes in [P3471R4](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3471r4.html) +(Standard Library Hardening) to the C++ working paper. + +LWG Poll 16. Apply the changes in [P0447R28](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0447r28.html) +(Introduction of `std::hive` to the standard library) to the C++ working paper. + +LWG Poll 17. Apply the changes in [P3019R14](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3019r14.pdf) +(`indirect` and `polymorphic`: Vocabulary Types for Composite Class Design) to the C++ working paper. + +## Editorial changes + +### Major editorial changes + +There have not been any major editorial changes. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N5001 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/n5001...n5008). + + commit f3676cb1550f1501236cc65c1dfa2dec957bbdf2 + Author: Mark Hoemmen + Date: Tue Dec 17 14:15:10 2024 -0700 + + [linalg.conj.conjugated] Remove inappropriate "expression-equivalent" wording (#7497) + + This phrase appears to be copy-pasted from elsewhere, but is not meaningful here. + + commit be0a25c9a2f2c1f498b0ff84a33c28adae41863e + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Dec 17 20:31:14 2024 +0100 + + [simd.alg] Fix range syntax + + commit a18040f05ff6a27e5c6425005ab1b21515ad952c + Author: Eisenwave + Date: Fri Nov 1 08:06:28 2024 +0100 + + [basic.compound] Update introduction + + commit 0131e015c09eca1901d0bfa46744a6c7ab31b00d + Author: Jonathan Wakely + Date: Tue Dec 17 21:21:42 2024 +0000 + + [linalg.helpers] Rename template parameter for poison pills + + This avoids reusing `T` which is also used for the type of the + subexpression E. + + Fixes #7494 + + commit 04169bac7059322ad8bf32e605a80e57ef30b922 + Author: Jens Maurer + Date: Tue Dec 17 22:51:01 2024 +0100 + + [inplace.vector.overview] Replace residual use of 'trivial type' + + commit 9272753d0ecbc1df9d08178793795f06b623a451 + Author: Hewill Kang + Date: Tue Nov 19 16:41:00 2024 +0800 + + [flat.map.defn, flat.set.defn] Avoid naming the from_range_t tag + + commit 85de0af0e0af416f7e73ac096254641c31bf11cc + Author: Jens Maurer + Date: Tue Dec 17 23:19:21 2024 +0100 + + [basic.fundamental] Ensure consistency with [conv.ptr] + + commit 561a4d8cde9e434fe206b88489e95b0e5271f469 + Author: Mark Hoemmen + Date: Thu Dec 19 14:35:50 2024 -0700 + + [bibliography] Fix spelling and formatting (#7507) + + Fix spelling of one author's name. Add missing commas + and extra spaces after a period ending authors' abbreviated + first or middle names. + + commit 82153790d8904ea82bc57edc8885b02925e85e93 + Author: Mark Hoemmen + Date: Thu Dec 19 14:41:02 2024 -0700 + + [simd.general, bibliography] Add SIMD acronym explanation and bibliographic reference (#7504) + + To the existing Note at the beginning of [simd.general], + add text that unpacks the SIMD acronym and refers to Flynn 1966. + + Add bibliography entry for Flynn 1966, the paper that introduced what + later became known as "Flynn's Taxonomy." This classifies parallel + computer hardware as SISD, SIMD, MISD, or MIMD. + + commit e1a368bc157f824cee7702e87a2cca1951e60f98 + Author: Jonathan Wakely + Date: Thu Dec 19 11:02:38 2024 +0000 + + [mdspan.sub] Change to "unit-stride slice for mapping" + + This was the wording requested by LWG and approved in P3355R2, but I + mistakenly put P3355R1 in the straw polls. + + commit 2d3ac367d8605d7172151726e873daea295a573a + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Dec 20 10:15:46 2024 +0100 + + [diff.cpp03.library] Correct \effect to \change + + - Correct \effect to \change. + - Add period at end. + - Add \tcode for swap. + + commit a2429a5944b71e3563dc09730426af43fb4b53e1 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Thu Dec 26 01:37:34 2024 +0000 + + [class.expl.init] Fix incorrect note + + commit 1411cf56fcb41f9fd000406185f17ef47235d26a + Author: Bronek Kozicki + Date: Wed Jan 1 17:00:14 2025 +0000 + + [expected.bad.void] Fix syntax error in bad_expected_access (#7529) + + Introduced by commit 8c997445c176c81a334e77f9344b91abc72b2772 + + commit a137940ac9c807e3ea809c3ff0b3a863795bf742 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Wed Jan 1 22:18:37 2025 +0100 + + [filebuf.members,fs.path.req] Fix indefinite article (#7530) + + commit d2b48043fcc219b2a141af39dae2eb85934c0847 + Author: Jens Maurer + Date: Thu Jan 2 10:49:14 2025 +0100 + + [expr.const] Properly merge P2686R5 + + P2686R5 (applied by commit e220906b71df01f09fe60921e8fac39b80558f78) + accidentally reverted a change considering erroneous values made by + P2795R5. + + commit 22937c04da139226c186973eda2cdb79df640b5b + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Thu Jan 2 15:14:06 2025 +0100 + + [format.arg] Fix indefinite article (#7536) + + commit 75af9f7f8cd816e1908eb2a3917eb7749c11471a + Author: Alisdair Meredith + Date: Sat Jan 4 02:18:53 2025 +0700 + + [tuple.helper] Remove redundant 'public' in base-specifier of struct (#7539) + + commit 6ff55d533f72b7222e022513dcb80982f4e887a0 + Author: Jens Maurer + Date: Mon Dec 30 16:34:49 2024 +0100 + + [lex.icon,depr.locale.category] Remove duplicate 'table' in front of table references + + commit 70df8aa8f4a30a7d54a604cbe01ebe13f5973043 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Wed Jan 8 13:51:13 2025 +0100 + + [linalg.algs.blas2.gemv] Fix singular/plural mismatch (#7546) + + commit 0164098f821ae002469c6f23cd03fc66a0a2f7ca + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Thu Jan 9 10:01:36 2025 +0000 + + [basic.def.odr] Fix typo and reference the correct subclause + + commit 2734ddeb05115f3fddf09c9c15b843083575e9df + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Jan 10 13:13:28 2025 +0100 + + [exec.async.ops] Remove stray closing parenthesis (#7555) + + commit 77171de904e6008f31717615d5baabf604baeea8 + Author: S. B. Tam + Date: Fri Jan 10 23:05:58 2025 +0800 + + [locale.time.put.members] Remove incorrect footnote (#7553) + + commit 6ecd1be67c71001db37883ee45b76cc66ef4101f + Author: Jens Maurer + Date: Mon Jan 13 22:34:47 2025 +0100 + + [exec.getcomplsigs] Add missing LaTeX escaping of braces (#7541) + + commit 1b1914ed868b0b29e63d0d1e4b872daf07b50740 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Jan 14 14:31:09 2025 +0100 + + [simd.traits] Remove stray closing parenthesis (#7563) + + commit 0ac6f9d7e94a70b48457f289bcbeb069a4662c28 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Wed Jan 15 14:10:57 2025 +0100 + + [locale.moneypunct.general] Insert period at end (#7564) + + commit 96fad4cf7ff48c8a4ae5442580d55008fb56ca43 + Author: Alisdair Meredith + Date: Wed Jan 15 10:06:49 2025 -0500 + + [inplace.vector.overview] Remove spurious semicolon closing namespace std (#7566) + + commit 1c398ffc71845163ca50b712f1edd9e1b2a87772 + Author: Jonathan Wakely + Date: Fri Jan 17 17:11:02 2025 +0000 + + [type.info] Remove comments explaining deleted members + + The standard is not a tutorial. + + commit 569e2a38cf1aa6d185b4c4d1817d9496ebd087e5 + Author: Jens Maurer + Date: Sat Jan 18 09:18:53 2025 +0100 + + [exec.snd.expos] Move write-env paragraph into itemdescr (#7571) + + commit 93aa7cb89b375280cb2d5f385fb0c5a5874e9243 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sat Jan 18 23:32:20 2025 +0100 + + [re.err,re.alg.match,re.tokiter.incr] Add period at end for consistency (#7574) + + commit ce5fd62b98d822228f46319f4516e34c492fa257 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Wed Jan 22 16:15:57 2025 +0100 + + [string.view.io,string.insert] Add period at end of "Returns" (#7579) + + commit 5c4823a05b83a67f7550fdcc1476f8000c29514c + Author: A. Jiang + Date: Thu Jan 23 11:31:05 2025 +0800 + + [expr.const] Re-apply CWG2909 + + commit db563eecdfb63cb24f10afb30f001a0bc6213997 + Author: Alisdair Meredith + Date: Wed Jan 15 07:59:51 2025 -0500 + + [lex.phases] Update implementation defined text + + Since C++23 we no longer have physical source files, but rather + input files. Update the two implementation-defined references + to the mapping from input file to translation character set + using the same phrasing so that they provide the same entry + in the index of implementation-defined behavior, just as they + did in C++20, before getting out of sync when the terminology + changed. + + commit a39cca2e9c009766da1e205daf5d7bf8cbdccaa3 + Author: Jonathan Wakely + Date: Thu Jan 23 07:28:40 2025 -0500 + + [linalg.conj.conjugated] Rearrange to match P3050R3 (#7506) + + This was the wording requested by LWG and approved in P3050R3, but I + mistakenly put P3050R2 in the straw polls. + + commit 6583c4ac9c2d3bbfb7daac0c79c902a30417c50f + Author: cor3ntin + Date: Sat Jan 25 14:11:30 2025 +0100 + + [std] Use template-parameter and template parameter more consistently (#7460) + + Try to use template-parameter only when we refer to a + grammar construct, and to 'template parameter' everywhere else. + + Adopt the same logic to template-argument/template argument. + + This change might not be exhaustive. + + The aim is to editorially adopt some of the wording changes + made in P2841R5 to ease its review in core. + + commit 696dcd809ceed3fc10502161963f8ce13505ec1a + Author: Jens Maurer + Date: Sat Jan 25 21:25:32 2025 +0100 + + [format.string.general,format.formatter.spec] Fix unparenthesized cross-references + + commit 47cf5a67357543b0d45d0072f42fdd29fa028cca + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Wed Jan 29 09:29:54 2025 +0100 + + [alg.rand.generate] Add period at end of "Returns" (#7595) + + commit b2b266e7b67eb583c50c34a9eceffe44f72ea2f6 + Author: Ivan Lazarić + Date: Sat Feb 1 09:56:42 2025 +0100 + + [temp.res.general] Fix nesting for \terminal{\opt{...}} (#7599) + + commit d51e6bedd991d55b7f7fb7f41e1f08083cfd1b1d + Author: Eric Niebler + Date: Mon Feb 3 12:05:48 2025 -0800 + + [range.view] Change incorrect uses of "which" to "that" (#7606) + + commit 1d49b05d1b48a2daa2a88d854e2367e6648c3cb6 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Mon Feb 3 21:14:45 2025 +0100 + + [tuple.assign] Remove incorrect comma at end (#7609) + + commit 2e1b856b6187fe9a5c74782948982eefd128ecbf + Author: Alisdair Meredith + Date: Mon Feb 3 16:17:48 2025 -0500 + + [diff.cpp.library] Add new C23 headers to list of new headers + + commit cae9b2a645d5bb91caffc061325f107605e85a0d + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Tue Feb 4 09:30:49 2025 +0100 + + [container.alloc.reqmts,sequence.reqmts] Add period at end (#7614) + + commit 003506a2779c519d4929cce75c7adeb1b7a76955 + Author: Alisdair Meredith + Date: Wed Jan 1 18:45:19 2025 +0700 + + [macros] Add LaTeX macros to index library macros + + The immediate idea is to support using the new macros directly + in header synopses when defining each library macro. This will + ensure that no macros are accidentally not indexed. + + A follow-up plan is that this separation of library macros will + make it easier to create a separate index of macros, or apply + other macro-specific renderings, in the future. To this end, + all indexed uses of a macro, not just those in header files, + should be replaced by use of these new macros. Similarly, + these LaTeX macros can be used in-place in regular text to + index cross-references where standard library macros are used + throughout the standard. + + commit d7618b4d20a24b37677b92c2fbd80dcee4565bc3 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Feb 7 09:37:37 2025 +0100 + + [diff.lex] Add period at end (#7618) + + commit 040ff41df1d0e0e4d31bd6c76f084fbc84239e7f + Author: Jonathan Wakely + Date: Sat Feb 8 07:56:45 2025 +0000 + + [fs.op.current.path] Remove note discussing design choices (#7620) + + commit dfdc64cbdc842f0f7d2a060440ea907b41ce78e6 + Author: Vlad Serebrennikov + Date: Sun Feb 9 20:12:44 2025 +0400 + + [basic.scope.scope] Update the note about special cases (#7594) + + commit 8948fd9bd8f799d50fc9cbff34b349b9d59157f1 + Author: André Brand + Date: Sun Feb 9 17:18:12 2025 +0100 + + [temp.mem.enum] Remove instantiation in example [temp.inst] (#7558) + + The example is inconsistent with [temp.inst]p3. Since the implicit instantiation + does not contribute to the point of [temp.mem.enum], the inconsistency + can be resolved by omitting the instantiation. + + commit 0d0ea5582082f85fa707c680634044209c2e343d + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Mon Nov 18 13:47:37 2024 +0000 + + [defns.argument] Mention braced-init-list + + commit 7566675c778f95ef966c4fea058a895def98e6d1 + Author: Alisdair Meredith + Date: Sun Feb 9 11:23:22 2025 -0500 + + [lex.phases] Use preprocessing token consistently (#7361) + + Prior to converting preprocessing tokens to tokens in phase 7, + all tokens are strictly preprocessing tokens. + + commit b9f054b0cba3a36f9c8eff0c190f85996597dc3d + Author: cor3ntin + Date: Mon Feb 10 07:47:58 2025 +0100 + + [std] Rename "non-type" to "constant" template parameter/argument (#7587) + + Note that not all instances of "non-type" have been mechanically replaced, + as [dcl] and [diff] use the term to refer to anything that is not a type + in the context of lookup. + + commit 45eb50507a1b6477dea6106c3c26654b96feae4a + Author: Alisdair Meredith + Date: Fri Jan 31 14:04:53 2025 -0500 + + [cmath.syn] Consolidate std namespaces + + There is no ordering dependency between the two typedefs + in namespace std, the macros that follow, and teh next + opening of namespace std, so move the two typedefs to + avoid repeatedly opening an closing the namespace. + + Note that we could have done this without moving + the typedefs as macros are not bound by namespaces, + but our convention very sensibly avoids confusing + readers by keeping macro definitions outside of + namespaces. + + commit 5eab5c6b456db2424b04becb791b23dbf4de356a + Author: Axel Naumann + Date: Mon Jan 27 15:50:24 2025 +0100 + + [class.prop] add ref to actual layout spec in [expr.rel] + + commit 2f42a31044cc1ec8cf119b0fd595fdcc1d625c59 + Author: A. Jiang + Date: Thu Jan 23 11:37:15 2025 +0800 + + [util.smartptr.atomic.{shared,weak}] Fix wording for initialization + + By using more conventional "value-initializes". + + commit 4e026ec784007b492eb3d904663cfdc4bf905fd3 + Author: Jonathan Wakely + Date: Tue Feb 4 11:09:05 2025 +0000 + + [fs.op.funcs] Remove empty parens when referring to functions by name + + As per the Specification Style Guidelines. + + https://github.com/cplusplus/draft/wiki/Specification-Style-Guidelines#describing-function-calls + + commit 7f00883b8f65307b7e0df0ad2e55182d699d2804 + Author: Jens Maurer + Date: Mon Jan 13 22:33:34 2025 +0100 + + [xrefdelta] Restore cross-references since C++17 + + commit 7fbdb79d99338d9aa91f382760ff6e1cb0353c71 + Author: Alisdair Meredith + Date: Tue Oct 1 09:20:10 2024 -0400 + + [except.uncaught] Tidy the specification for uncaught exceptions + + Several concurrent fixes. First include the normative wording + that 'uncaught_exceptions' returns the number of uncaught + exceptions *on the current thread*. This wording is present + in the core language. + + Then move the core wording for when an exception is uncaught + directly into the text that talks about caught and uncaught + exceptions. In the process, turn the reference to into a note, + so that there is only one normative specification. + + Finally, remove [except.uncaught] as it is now empty. + + commit 70abf300ddbb1074cd16e9a5febe7f7c88bdff3d + Author: Alisdair Meredith + Date: Wed Nov 20 02:07:51 2024 +0100 + + [except.special.general] Complete the set of clause 17 references + + commit 888b0510da303e367f7421ac34607a158ddfc453 + Author: Alisdair Meredith + Date: Tue Jan 21 04:31:34 2025 -0500 + + [basic.pre] Defragment specification of names and entities + + The current contents of [basic.pre] jump between specifying + different things. This PR moves all the specification of + names to the front, followed by the specification of entities. + + There are two main benefits: (1) the specification for when + two names are the same is a list of 4 rules that correspond + to the 4 things than can form a name --- the connection is + much clearer when the paragraphs are adjacent and the list + is sorted to the same order; (2) in this form, even though + all the words are the same, the reordering and merging of + paragraphs a fit on a single page. The very last paragraph + was forced over a page-break in the original layout. + + commit 5be40a6b59527e82b13a29722c623635065759bf + Author: Thomas Köppe + Date: Tue Feb 11 21:42:20 2025 +0100 + + [expr.lval] Update cross reference for "invalid pointer value" + + commit 83530f54892686c9ba055434d02dfadc00bbb290 + Author: A. Jiang + Date: Thu Aug 3 00:54:57 2023 +0800 + + [basic.extended.fp] Use "declared" for typedef-names + + commit 1542d983b3f690876720d69a44dff2c5574617b3 + Author: A. Jiang + Date: Thu Aug 3 01:00:16 2023 +0800 + + [expr.{add,alignof,sizeof}] Use "typedef-name", avoid "defined" + + commit 152693b46648ea99493aecedbc8051aa2ab7542f + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Wed Feb 12 17:58:51 2025 +0000 + + [temp.param, temp.constr.normal] Use \dotsc for a non-code ellipsis (#7397) + + commit 930b8f97b0ab7bd9442bd0faf10f7302da5fc89a + Author: Alisdair Meredith + Date: Wed Feb 12 19:22:47 2025 +0100 + + [diff.cpp03.library] Fix cross-reference to restriction on macro names + + commit 2cfc175a01d2bff1daf084d5c776017c5c049872 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Thu Feb 13 22:28:24 2025 +0000 + + [linalg.general] Remove extraneous dot (#7637) + + commit 422ded52d1876578f4eeb3bc30d583a193b94f42 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Fri Feb 14 19:13:02 2025 +0100 + + [conv.rank] Fix typo + + commit 10468bf63eee8926b84b76a10abb2a7d05b43c02 + Author: Andreas Krug <153394595+Andreas-Krug@users.noreply.github.com> + Date: Sun Feb 16 12:13:43 2025 +0100 + + [map.overview] Fix punctuation (#7677) + + commit a103bf3ea67a731189a8f1453d3e9ab88d589eba + Author: Alisdair Meredith + Date: Mon Feb 24 07:46:22 2025 -0500 + + [xrefdelta] Consolidate restored entries (#7631) + + Several entries in the restored larger delta referred + to stable labels that have since moved again, or have been + removed. This commit updates their cross-references + accordingly, or marks them as removed if appropriate. + + commit 9854e729ba5ade9a41bf047b6a5fe6f4bbe038e0 + Author: Hubert Tong + Date: Thu Feb 13 17:01:13 2025 -0500 + + [basic.types.general] Change ordering to "non-variant non-static" + + The definition of literal type is the only place where "non-static + non-variant data member" is used as opposed to "non-variant non-static + data member". + + Change to use the canonical ordering. + + commit c31b8f4111dfa9dd598220b9c6f8c1cf9d4a9b34 + Author: Jonathan Wakely + Date: Tue Feb 25 09:54:40 2025 +0000 + + [support.srcloc.cons] Update xref to [class.mem.general] + + The cross-reference to [class.mem] was referring to a hanging paragraph + that was fixed by 2850139be6285ba10a64fb718125a80ca967c631 so we should + be referring to [class.mem.general] now. + + commit 912e5cab7565be0daa9c0c6d7c178600b3cd38e6 + Author: lprv <100177227+lprv@users.noreply.github.com> + Date: Sat Mar 15 20:23:43 2025 +0000 + + [functional.{syn,bind.place}] Use \vdots; add missing \placeholder (#7723) + + commit 0dda8468be890adf880afddc37e449cbc40607cb + Author: A. Jiang + Date: Sun Mar 16 04:26:10 2025 +0800 + + [expr.const] Change "value" to "result object" (of a prvalue) (#6267) + + commit 4552a92a01a2d1b032264cd6568a860a5244918b + Author: Jens Maurer + Date: Sun Nov 7 22:35:21 2021 +0100 + + [lex.string] Clarify size of string-literal + + commit ec10aaec4e6daac66b7b28426abcc765494194c9 + Author: Hubert Tong + Date: Sat Mar 15 16:41:54 2025 -0400 + + [debugging.utility] Clarify wording in notes + + The previous wording in the notes in `breakpoint` and `is_debugger_present` + read as statements of fact about the implementation-defined behaviour. + The statements are actually ones of intent. + + The specific claim in `breakpoint` that the debugger resumes execution of the program + as if the function was not invoked is confusing considering that the debugger may effect + side-effects or cause execution to resume from a different evaluation. + + Instead, the idea is that `breakpoint` is not responsible for causing the translation process + to make special accomodations for resumption of execution other than in cases + where the debugger was strictly used for observation only. + + In `is_debugger_present`, the functionality ascribed to POSIX by the wording + ("ptrace") is not present in POSIX. Update to reference the LSB and to use + the corresponding terminology ("tracing process"). + + The wording implies a preference to return `true` in case it is unknown + whether a debugger is present. Add a critical "only" to fix that. + + commit 598910dc970bc0bc840ba797983e9bc131cd826e + Author: A. Jiang + Date: Tue Feb 25 07:51:44 2025 +0800 + + [ifstream.members] Remove mistakenly added `@` + + commit 4b5a0080230ed74d796a3ee909bdde66e2f2b395 + Author: A. Jiang + Date: Wed Aug 7 18:45:41 2024 +0800 + + [func.wrap.func] Drop Lvalue-Callable + + Replace its usages with `is_invocable_r_v` and remove an unnecessary index. + + commit f9847af90413adb0436aae9f6895b4a2e0e173ec + Author: A. Jiang + Date: Mon Feb 17 11:44:11 2025 +0800 + + [containers, strings, algorithms, re] Use \range where appropriate + + Currently, there are several cases where `\tcode{[i, j)}` is used for + specifying left-closed right-open intervals, where `\range{i}{j}` is proper. + + Co-authored-by: Eelis van der Weegen + + commit 73699cf37d247a7c1f3a6879197c730a14666b90 + Author: languagelawyer <38548419+languagelawyer@users.noreply.github.com> + Date: Fri Feb 26 02:55:52 2021 +0300 + + [class.cdtor] Only objects of scalar type can be accessed + diff --git a/papers/wd-index.md b/papers/wd-index.md index c7e0741fd5..92100a86b8 100644 --- a/papers/wd-index.md +++ b/papers/wd-index.md @@ -47,3 +47,10 @@ * [N4950](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4950.pdf) 2023-05 C++ Working Draft * [N4958](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4958.pdf) 2023-08 C++ Working Draft * [N4964](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4964.pdf) 2023-10 C++ Working Draft + * [N4971](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4971.pdf) 2023-12 C++ Working Draft + * [N4981](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4981.pdf) 2024-03 C++ Working Draft + * [N4986](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4986.pdf) 2024-06 C++ Working Draft + * [N4988](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf) 2024-08 C++ Working Draft + * [N4993](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4993.pdf) 2024-10 C++ Working Draft + * [N5001](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n5001.pdf) 2024-12 C++ Working Draft + * [N5008](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5008.pdf) 2025-03 C++ Working Draft diff --git a/source/algorithms.tex b/source/algorithms.tex index ffe860726a..4c85cac4da 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -12,19 +12,20 @@ non-modifying sequence operations, mutating sequence operations, sorting and related operations, -and algorithms from the ISO C library, +and algorithms from the C library, as summarized in \tref{algorithms.summary}. \begin{libsumtab}{Algorithms library summary}{algorithms.summary} \ref{algorithms.requirements} & Algorithms requirements & \\ -\ref{algorithms.parallel} & Parallel algorithms & \\ \rowsep -\ref{algorithms.results} & Algorithm result types & \tcode{} \\ +\ref{algorithms.parallel} & Parallel algorithms & \tcode{} \\ \rowsep +\ref{algorithms.results} & Algorithm result types & \tcode{} \\ \ref{alg.nonmodifying} & Non-modifying sequence operations & \\ \ref{alg.modifying.operations} & Mutating sequence operations & \\ \ref{alg.sorting} & Sorting and related operations & \\ \rowsep -\ref{numeric.ops} & Generalized numeric operations & \tcode{} \\ \rowsep +\ref{numeric.ops} & Generalized numeric operations & \tcode{} \\ \rowsep \ref{specialized.algorithms} & Specialized \tcode{} algorithms & \tcode{} \\ \rowsep -\ref{alg.c.library} & C library algorithms & \tcode{} \\ +\ref{alg.rand} & Specialized \tcode{} algorithms & \tcode{} \\ \rowsep +\ref{alg.c.library} & C library algorithms & \tcode{} \\ \end{libsumtab} \rSec1[algorithms.requirements]{Algorithms requirements} @@ -37,28 +38,9 @@ satisfying the assumptions on the algorithms. \pnum -The entities defined in the \tcode{std::ranges} namespace in this Clause -are not found by argument-dependent name lookup\iref{basic.lookup.argdep}. -When found by 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. - -\begin{example} -\begin{codeblock} -void foo() { - using namespace std::ranges; - std::vector vec{1,2,3}; - find(begin(vec), end(vec), 2); // \#1 -} -\end{codeblock} -The function call expression at \tcode{\#1} invokes \tcode{std::ranges::find}, -not \tcode{std::find}, despite that -(a) the iterator type returned from \tcode{begin(vec)} and \tcode{end(vec)} -may be associated with namespace \tcode{std} and -(b) \tcode{std::find} is more specialized\iref{temp.func.order} than -\tcode{std::ranges::find} since the former requires -its first two parameters to have the same type. -\end{example} +The entities defined in the \tcode{std::ranges} namespace in this Clause and +specified as function templates are +algorithm function objects\iref{alg.func.obj}. \pnum For purposes of determining the existence of data races, @@ -297,7 +279,7 @@ by invoking the following functions: \begin{itemize} \item - All operations of the categories of the iterators + All operations of the categories of the iterators or \tcode{mdspan} types that the algorithm is instantiated with. \item Operations on those sequence elements that are required by its specification. @@ -348,7 +330,7 @@ int a[] = {1,2}; std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) { std::lock_guard guard(m); // incorrect: \tcode{lock_guard} constructor calls \tcode{m.lock()} - ++x; + ++x; }); } \end{codeblock} @@ -369,7 +351,8 @@ \tcode{UnaryOperation}, \tcode{BinaryOperation}, \tcode{BinaryOperation1}, -\tcode{BinaryOperation2}, and +\tcode{BinaryOperation2}, +\tcode{BinaryDivideOp}, and the operators used by the analogous overloads to these parallel algorithms that are formed by an invocation with the specified default predicate or operation (where applicable) @@ -618,10 +601,178 @@ Parallel algorithms shall not participate in overload resolution unless \tcode{is_execution_policy_v>} is \tcode{true}. +\rSec2[execpol]{Execution policies} + +\rSec3[execpol.general]{General} + +\pnum +Subclause~\ref{execpol} describes classes that are \defn{execution policy} types. An +object of an execution policy type indicates the kinds of parallelism allowed +in the execution of an algorithm and expresses the consequent requirements on +the element access functions. +Execution policy types are declared in header \libheaderref{execution}. +\begin{example} +\begin{codeblock} +using namespace std; +vector v = @\commentellip@; + +// standard sequential sort +sort(v.begin(), v.end()); + +// explicitly sequential sort +sort(execution::seq, v.begin(), v.end()); + +// permitting parallel execution +sort(execution::par, v.begin(), v.end()); + +// permitting vectorization as well +sort(execution::par_unseq, v.begin(), v.end()); +\end{codeblock} +\end{example} +\begin{note} +Implementations can provide additional execution policies +to those described in this document as extensions +to address parallel architectures that require idiosyncratic +parameters for efficient execution. +\end{note} + +\rSec3[execpol.type]{Execution policy type trait} + +\indexlibraryglobal{is_execution_policy}% +\begin{itemdecl} +template struct is_execution_policy { @\seebelow@ }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{is_execution_policy} can be used to detect execution policies for the +purpose of excluding function signatures from otherwise ambiguous overload +resolution participation. + +\pnum +\tcode{is_execution_policy} is a \oldconcept{UnaryTypeTrait} with a +base characteristic of \tcode{true_type} if \tcode{T} is the type of a standard +or \impldef{additional execution policies supported by parallel algorithms} +execution policy, otherwise \tcode{false_type}. + +\begin{note} +This provision reserves the privilege of creating non-standard execution +policies to the library implementation. +\end{note} + +\pnum +The behavior of a program that adds specializations for +\tcode{is_execution_policy} is undefined. +\end{itemdescr} + +\rSec3[execpol.seq]{Sequenced execution policy} + +\indexlibraryglobal{execution::sequenced_policy}% +\begin{itemdecl} +class execution::sequenced_policy { @\unspec@ }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The class \tcode{execution::sequenced_policy} is an execution policy type used +as a unique type to disambiguate parallel algorithm overloading and require +that a parallel algorithm's execution may not be parallelized. + +\pnum +During the execution of a parallel algorithm with +the \tcode{execution::sequenced_policy} policy, +if the invocation of an element access function exits via an exception, +\tcode{terminate} is invoked\iref{except.terminate}. +\end{itemdescr} + +\rSec3[execpol.par]{Parallel execution policy} + +\indexlibraryglobal{execution::parallel_policy}% +\begin{itemdecl} +class execution::parallel_policy { @\unspec@ }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The class \tcode{execution::parallel_policy} is an execution policy type used as +a unique type to disambiguate parallel algorithm overloading and indicate that +a parallel algorithm's execution may be parallelized. + +\pnum +During the execution of a parallel algorithm with +the \tcode{execution::parallel_policy} policy, +if the invocation of an element access function exits via an exception, +\tcode{terminate} is invoked\iref{except.terminate}. +\end{itemdescr} + +\rSec3[execpol.parunseq]{Parallel and unsequenced execution policy} + +\indexlibraryglobal{execution::parallel_unsequenced_policy}% +\begin{itemdecl} +class execution::parallel_unsequenced_policy { @\unspec@ }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The class \tcode{execution::parallel_unsequenced_policy} is an execution policy type +used as a unique type to disambiguate parallel algorithm overloading and +indicate that a parallel algorithm's execution may be parallelized and +vectorized. + +\pnum +During the execution of a parallel algorithm with +the \tcode{execution::parallel_unsequenced_policy} policy, +if the invocation of an element access function exits via an exception, +\tcode{terminate} is invoked\iref{except.terminate}. +\end{itemdescr} + +\rSec3[execpol.unseq]{Unsequenced execution policy} + +\indexlibraryglobal{execution::unsequenced_policy}% +\begin{itemdecl} +class execution::unsequenced_policy { @\unspec@ }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The class \tcode{unsequenced_policy} is an execution policy type +used as a unique type to disambiguate parallel algorithm overloading and +indicate that a parallel algorithm's execution may be vectorized, +e.g., executed on a single thread using instructions +that operate on multiple data items. + +\pnum +During the execution of a parallel algorithm with +the \tcode{execution::unsequenced_policy} policy, +if the invocation of an element access function exits via an exception, +\tcode{terminate} is invoked\iref{except.terminate}. +\end{itemdescr} + +\rSec3[execpol.objects]{Execution policy objects} + +\indexlibraryglobal{seq}% +\indexlibraryglobal{par}% +\indexlibraryglobal{par_unseq}% +\indexlibrarymember{execution}{seq}% +\indexlibrarymember{execution}{par}% +\indexlibrarymember{execution}{par_unseq}% +\begin{itemdecl} +inline constexpr execution::sequenced_policy execution::seq{ @\unspec@ }; +inline constexpr execution::parallel_policy execution::par{ @\unspec@ }; +inline constexpr execution::parallel_unsequenced_policy execution::par_unseq{ @\unspec@ }; +inline constexpr execution::unsequenced_policy execution::unseq{ @\unspec@ }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The header \libheaderref{execution} declares global objects associated with each type of execution policy. +\end{itemdescr} + \rSec1[algorithm.syn]{Header \tcode{} synopsis} \indexheader{algorithm}% \begin{codeblock} +// mostly freestanding #include // see \ref{initializer.list.syn} namespace std { @@ -660,7 +811,7 @@ template constexpr bool all_of(InputIterator first, InputIterator last, Predicate pred); template - bool all_of(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool all_of(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { @@ -676,7 +827,7 @@ template constexpr bool any_of(InputIterator first, InputIterator last, Predicate pred); template - bool any_of(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool any_of(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { @@ -692,7 +843,7 @@ template constexpr bool none_of(InputIterator first, InputIterator last, Predicate pred); template - bool none_of(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool none_of(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { @@ -706,10 +857,12 @@ // \ref{alg.contains}, contains namespace ranges { - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr bool contains(I first, S last, const T& value, Proj proj = {}); - template<@\libconcept{input_range}@ R, class T, class Proj = identity> + template<@\libconcept{input_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr bool contains(R&& r, const T& value, Proj proj = {}); @@ -731,7 +884,7 @@ template constexpr Function for_each(InputIterator first, InputIterator last, Function f); template - void for_each(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void for_each(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Function f); namespace ranges { @@ -751,7 +904,7 @@ template constexpr InputIterator for_each_n(InputIterator first, Size n, Function f); template - ForwardIterator for_each_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator for_each_n(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, Size n, Function f); namespace ranges { @@ -765,33 +918,36 @@ } // \ref{alg.find}, find - template + template::value_type> constexpr InputIterator find(InputIterator first, InputIterator last, const T& value); - template - ForwardIterator find(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + template::value_type> + ForwardIterator find(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, const T& value); template constexpr InputIterator find_if(InputIterator first, InputIterator last, Predicate pred); template - ForwardIterator find_if(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator find_if(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); template constexpr InputIterator find_if_not(InputIterator first, InputIterator last, Predicate pred); template - ForwardIterator find_if_not(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator find_if_not(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr I find(I first, S last, const T& value, Proj proj = {}); - template<@\libconcept{input_range}@ R, class T, class Proj = identity> + template<@\libconcept{input_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr borrowed_iterator_t @@ -847,13 +1003,13 @@ BinaryPredicate pred); template ForwardIterator1 - find_end(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + find_end(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template ForwardIterator1 - find_end(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + find_end(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); @@ -885,13 +1041,13 @@ BinaryPredicate pred); template ForwardIterator1 - find_first_of(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + find_first_of(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template ForwardIterator1 - find_first_of(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + find_first_of(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); @@ -920,11 +1076,11 @@ BinaryPredicate pred); template ForwardIterator - adjacent_find(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + adjacent_find(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template ForwardIterator - adjacent_find(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + adjacent_find(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, BinaryPredicate pred); @@ -942,27 +1098,30 @@ } // \ref{alg.count}, count - template + template::value_type> constexpr typename iterator_traits::difference_type count(InputIterator first, InputIterator last, const T& value); - template + template::value_type> typename iterator_traits::difference_type - count(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + count(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, const T& value); template constexpr typename iterator_traits::difference_type count_if(InputIterator first, InputIterator last, Predicate pred); template typename iterator_traits::difference_type - count_if(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + count_if(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr iter_difference_t count(I first, S last, const T& value, Proj proj = {}); - template<@\libconcept{input_range}@ R, class T, class Proj = identity> + template<@\libconcept{input_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr range_difference_t @@ -997,24 +1156,24 @@ BinaryPredicate pred); template pair - mismatch(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + mismatch(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2); template pair - mismatch(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + mismatch(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, BinaryPredicate pred); template pair - mismatch(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + mismatch(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template pair - mismatch(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + mismatch(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); @@ -1052,21 +1211,21 @@ InputIterator2 first2, InputIterator2 last2, BinaryPredicate pred); template - bool equal(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool equal(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2); template - bool equal(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool equal(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, BinaryPredicate pred); template - bool equal(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool equal(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template - bool equal(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool equal(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); @@ -1129,13 +1288,13 @@ BinaryPredicate pred); template ForwardIterator1 - search(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + search(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template ForwardIterator1 - search(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + search(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); @@ -1156,36 +1315,40 @@ Proj1 proj1 = {}, Proj2 proj2 = {}); } - template + template::value_type> constexpr ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, const T& value); - template + template::value_type, class BinaryPredicate> constexpr ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, const T& value, BinaryPredicate pred); - template + template::value_type> ForwardIterator - search_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + search_n(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Size count, const T& value); - template + template::value_type, class BinaryPredicate> ForwardIterator - search_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + search_n(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Size count, const T& value, BinaryPredicate pred); namespace ranges { - template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, - class Pred = ranges::equal_to, class Proj = identity> + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, + class Pred = ranges::equal_to, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirectly_comparable}@ constexpr subrange search_n(I first, S last, iter_difference_t count, const T& value, Pred pred = {}, Proj proj = {}); - template<@\libconcept{forward_range}@ R, class T, class Pred = ranges::equal_to, - class Proj = identity> + template<@\libconcept{forward_range}@ R, class Pred = ranges::equal_to, + class Proj = identity, class T = projected_value_t> requires @\libconcept{indirectly_comparable}@, const T*, Pred, Proj> constexpr borrowed_subrange_t search_n(R&& r, range_difference_t count, @@ -1254,11 +1417,12 @@ concept @\defexposconcept{indirectly-binary-right-foldable}@ = // \expos @\exposconcept{indirectly-binary-left-foldable}@<@\exposid{flipped}@, T, I>; - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T = iter_value_t, @\exposconcept{indirectly-binary-left-foldable}@ F> constexpr auto fold_left(I first, S last, T init, F f); - template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@> F> + template<@\libconcept{input_range}@ R, class T = range_value_t, + @\exposconcept{indirectly-binary-left-foldable}@> F> constexpr auto fold_left(R&& r, T init, F f); template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, @@ -1270,18 +1434,18 @@ requires @\libconcept{constructible_from}@, range_reference_t> constexpr auto fold_left_first(R&& r, F f); - template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, + template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, class T = iter_value_t, @\exposconcept{indirectly-binary-right-foldable}@ F> constexpr auto fold_right(I first, S last, T init, F f); - template<@\libconcept{bidirectional_range}@ R, class T, + template<@\libconcept{bidirectional_range}@ R, class T = range_value_t, @\exposconcept{indirectly-binary-right-foldable}@> F> constexpr auto fold_right(R&& r, T init, F f); template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, @\exposconcept{indirectly-binary-right-foldable}@, I> F> requires @\libconcept{constructible_from}@, iter_reference_t> - constexpr auto fold_right_last(I first, S last, F f); + constexpr auto fold_right_last(I first, S last, F f); template<@\libconcept{bidirectional_range}@ R, @\exposconcept{indirectly-binary-right-foldable}@, iterator_t> F> @@ -1293,11 +1457,12 @@ template using fold_left_first_with_iter_result = in_value_result; - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T = iter_value_t, @\exposconcept{indirectly-binary-left-foldable}@ F> constexpr @\seebelow@ fold_left_with_iter(I first, S last, T init, F f); - template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@> F> + template<@\libconcept{input_range}@ R, class T = range_value_t, + @\exposconcept{indirectly-binary-left-foldable}@> F> constexpr @\seebelow@ fold_left_with_iter(R&& r, T init, F f); template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, @@ -1317,7 +1482,7 @@ constexpr OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result); template - ForwardIterator2 copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator2 copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); @@ -1340,7 +1505,7 @@ OutputIterator result); template - ForwardIterator2 copy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator2 copy_n(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, Size n, ForwardIterator2 result); @@ -1359,7 +1524,7 @@ OutputIterator result, Predicate pred); template - ForwardIterator2 copy_if(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator2 copy_if(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, Predicate pred); @@ -1404,7 +1569,7 @@ OutputIterator result); template - ForwardIterator2 move(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator2 move(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); @@ -1446,7 +1611,7 @@ constexpr ForwardIterator2 swap_ranges(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2); template - ForwardIterator2 swap_ranges(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator2 swap_ranges(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2); @@ -1481,13 +1646,13 @@ template ForwardIterator2 - transform(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + transform(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 result, UnaryOperation op); template ForwardIterator - transform(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + transform(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator result, BinaryOperation binary_op); @@ -1514,14 +1679,14 @@ @\libconcept{weakly_incrementable}@ O, @\libconcept{copy_constructible}@ F, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, - projected>> + projected>> constexpr binary_transform_result transform(I1 first1, S1 last1, I2 first2, S2 last2, O result, F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); template<@\libconcept{input_range}@ R1, @\libconcept{input_range}@ R2, @\libconcept{weakly_incrementable}@ O, @\libconcept{copy_constructible}@ F, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, Proj1>, - projected, Proj2>>> + projected, Proj2>>> constexpr binary_transform_result, borrowed_iterator_t, O> transform(R1&& r1, R2&& r2, O result, F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -1531,35 +1696,41 @@ template constexpr void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value); - template - void replace(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + template::value_type> + void replace(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value); - template + template::value_type> constexpr void replace_if(ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value); - template - void replace_if(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + template::value_type> + void replace_if(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value); namespace ranges { - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T1, class T2, class Proj = identity> + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T1 = projected_value_t, class T2 = T1> requires @\libconcept{indirectly_writable}@ && @\libconcept{indirect_binary_predicate}@, const T1*> constexpr I replace(I first, S last, const T1& old_value, const T2& new_value, Proj proj = {}); - template<@\libconcept{input_range}@ R, class T1, class T2, class Proj = identity> + template<@\libconcept{input_range}@ R, class Proj = identity, + class T1 = projected_value_t, Proj>, class T2 = T1> requires @\libconcept{indirectly_writable}@, const T2&> && @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> constexpr borrowed_iterator_t replace(R&& r, const T1& old_value, const T2& new_value, Proj proj = {}); - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_unary_predicate}@> Pred> requires @\libconcept{indirectly_writable}@ constexpr I replace_if(I first, S last, Pred pred, const T& new_value, Proj proj = {}); - template<@\libconcept{input_range}@ R, class T, class Proj = identity, + template<@\libconcept{input_range}@ R, class Proj = identity, class T = projected_value_t, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> requires @\libconcept{indirectly_writable}@, const T&> constexpr borrowed_iterator_t @@ -1571,17 +1742,18 @@ OutputIterator result, const T& old_value, const T& new_value); template - ForwardIterator2 replace_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator2 replace_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, const T& old_value, const T& new_value); - template + template::value_type> constexpr OutputIterator replace_copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate pred, const T& new_value); template - ForwardIterator2 replace_copy_if(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + class Predicate, class T = iterator_traits::value_type> + ForwardIterator2 replace_copy_if(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, Predicate pred, const T& new_value); @@ -1590,18 +1762,21 @@ template using replace_copy_result = in_out_result; - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T1, class T2, - @\libconcept{output_iterator}@ O, class Proj = identity> + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class O, + class Proj = identity, + class T1 = projected_value_t, class T2 = iter_value_t> requires @\libconcept{indirectly_copyable}@ && - @\libconcept{indirect_binary_predicate}@, const T1*> + @\libconcept{indirect_binary_predicate}@, const T1*> && + @\libconcept{output_iterator}@ constexpr replace_copy_result replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value, Proj proj = {}); - template<@\libconcept{input_range}@ R, class T1, class T2, @\libconcept{output_iterator}@ O, - class Proj = identity> + template<@\libconcept{input_range}@ R, class O, class Proj = identity, + class T1 = projected_value_t, Proj>, class T2 = iter_value_t> requires @\libconcept{indirectly_copyable}@, O> && @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> + projected, Proj>, const T1*> && + @\libconcept{output_iterator}@ constexpr replace_copy_result, O> replace_copy(R&& r, O result, const T1& old_value, const T2& new_value, Proj proj = {}); @@ -1609,39 +1784,44 @@ template using replace_copy_if_result = in_out_result; - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, @\libconcept{output_iterator}@ O, + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class O, class T = iter_value_t class Proj = identity, @\libconcept{indirect_unary_predicate}@> Pred> - requires @\libconcept{indirectly_copyable}@ + requires @\libconcept{indirectly_copyable}@ && @\libconcept{output_iterator}@ constexpr replace_copy_if_result replace_copy_if(I first, S last, O result, Pred pred, const T& new_value, Proj proj = {}); - template<@\libconcept{input_range}@ R, class T, @\libconcept{output_iterator}@ O, class Proj = identity, + template<@\libconcept{input_range}@ R, class O, class T = iter_value_t, class Proj = identity, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> - requires @\libconcept{indirectly_copyable}@, O> + requires @\libconcept{indirectly_copyable}@, O> && @\libconcept{output_iterator}@ constexpr replace_copy_if_result, O> replace_copy_if(R&& r, O result, Pred pred, const T& new_value, Proj proj = {}); } // \ref{alg.fill}, fill - template + template::value_type> constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value); - template - void fill(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + template::value_type> + void fill(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, const T& value); - template - constexpr OutputIterator fill_n(OutputIterator first, Size n, const T& value); + template::value_type> + constexpr OutputIterator fill_n(OutputIterator first, Size n, const T& value) template - ForwardIterator fill_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + class Size, class T = iterator_traits::value_type> + ForwardIterator fill_n(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, Size n, const T& value); namespace ranges { - template O, @\libconcept{sentinel_for}@ S> + template S, class T = iter_value_t> + requires @\libconcept{output_iterator}@ constexpr O fill(O first, S last, const T& value); - template R> + template> + requires @\libconcept{output_range}@ constexpr borrowed_iterator_t fill(R&& r, const T& value); - template O> + template> + requires @\libconcept{output_iterator}@ constexpr O fill_n(O first, iter_difference_t n, const T& value); } @@ -1650,13 +1830,13 @@ constexpr void generate(ForwardIterator first, ForwardIterator last, Generator gen); template - void generate(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void generate(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Generator gen); template constexpr OutputIterator generate_n(OutputIterator first, Size n, Generator gen); template - ForwardIterator generate_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator generate_n(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, Size n, Generator gen); namespace ranges { @@ -1672,26 +1852,29 @@ } // \ref{alg.remove}, remove - template + template::value_type> constexpr ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value); - template - ForwardIterator remove(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + template::value_type> + ForwardIterator remove(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, const T& value); template constexpr ForwardIterator remove_if(ForwardIterator first, ForwardIterator last, Predicate pred); template - ForwardIterator remove_if(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator remove_if(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template<@\libconcept{permutable}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + template<@\libconcept{permutable}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr subrange remove(I first, S last, const T& value, Proj proj = {}); - template<@\libconcept{forward_range}@ R, class T, class Proj = identity> + template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{permutable}@> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> @@ -1707,14 +1890,15 @@ remove_if(R&& r, Pred pred, Proj proj = {}); } - template + template::value_type> constexpr OutputIterator remove_copy(InputIterator first, InputIterator last, OutputIterator result, const T& value); template + class T = iterator_traits::value_type> ForwardIterator2 - remove_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + remove_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, const T& value); template @@ -1724,7 +1908,7 @@ template ForwardIterator2 - remove_copy_if(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + remove_copy_if(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, Predicate pred); @@ -1732,13 +1916,14 @@ template using remove_copy_result = in_out_result; - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, @\libconcept{weakly_incrementable}@ O, class T, - class Proj = identity> + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, @\libconcept{weakly_incrementable}@ O, + class Proj = identity, class T = projected_value_t> requires @\libconcept{indirectly_copyable}@ && @\libconcept{indirect_binary_predicate}@, const T*> constexpr remove_copy_result remove_copy(I first, S last, O result, const T& value, Proj proj = {}); - template<@\libconcept{input_range}@ R, @\libconcept{weakly_incrementable}@ O, class T, class Proj = identity> + template<@\libconcept{input_range}@ R, @\libconcept{weakly_incrementable}@ O, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{indirectly_copyable}@, O> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> @@ -1767,10 +1952,10 @@ constexpr ForwardIterator unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred); template - ForwardIterator unique(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator unique(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template - ForwardIterator unique(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator unique(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, BinaryPredicate pred); @@ -1795,13 +1980,13 @@ OutputIterator result, BinaryPredicate pred); template ForwardIterator2 - unique_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + unique_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); template ForwardIterator2 - unique_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + unique_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryPredicate pred); @@ -1831,7 +2016,7 @@ template constexpr void reverse(BidirectionalIterator first, BidirectionalIterator last); template - void reverse(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void reverse(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} BidirectionalIterator first, BidirectionalIterator last); namespace ranges { @@ -1849,7 +2034,7 @@ OutputIterator result); template ForwardIterator - reverse_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + reverse_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} BidirectionalIterator first, BidirectionalIterator last, ForwardIterator result); @@ -1873,7 +2058,7 @@ ForwardIterator middle, ForwardIterator last); template - ForwardIterator rotate(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator rotate(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator middle, ForwardIterator last); @@ -1892,7 +2077,7 @@ ForwardIterator last, OutputIterator result); template ForwardIterator2 - rotate_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + rotate_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 middle, ForwardIterator1 last, ForwardIterator2 result); @@ -1955,7 +2140,7 @@ typename iterator_traits::difference_type n); template ForwardIterator - shift_left(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + shift_left(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, typename iterator_traits::difference_type n); @@ -1973,7 +2158,7 @@ typename iterator_traits::difference_type n); template ForwardIterator - shift_right(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + shift_right(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, typename iterator_traits::difference_type n); @@ -1993,10 +2178,10 @@ constexpr void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp); template - void sort(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void sort(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last); template - void sort(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void sort(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last, Compare comp); @@ -2013,15 +2198,15 @@ } template - constexpr void stable_sort(RandomAccessIterator first, RandomAccessIterator last); + constexpr void stable_sort(RandomAccessIterator first, RandomAccessIterator last); // hosted template - constexpr void stable_sort(RandomAccessIterator first, RandomAccessIterator last, - Compare comp); + constexpr void stable_sort(RandomAccessIterator first, RandomAccessIterator last, // hosted + Compare comp); template - void stable_sort(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void stable_sort(ExecutionPolicy&& exec, // hosted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last); template - void stable_sort(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void stable_sort(ExecutionPolicy&& exec, // hosted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last, Compare comp); @@ -2029,11 +2214,11 @@ template<@\libconcept{random_access_iterator}@ I, @\libconcept{sentinel_for}@ S, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@ - constexpr I stable_sort(I first, S last, Comp comp = {}, Proj proj = {}); + constexpr I stable_sort(I first, S last, Comp comp = {}, Proj proj = {}); // hosted template<@\libconcept{random_access_range}@ R, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@, Comp, Proj> constexpr borrowed_iterator_t - stable_sort(R&& r, Comp comp = {}, Proj proj = {}); + stable_sort(R&& r, Comp comp = {}, Proj proj = {}); // hosted } template @@ -2043,11 +2228,11 @@ constexpr void partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp); template - void partial_sort(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void partial_sort(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last); template - void partial_sort(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void partial_sort(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp); @@ -2077,14 +2262,14 @@ Compare comp); template RandomAccessIterator - partial_sort_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + partial_sort_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last); template RandomAccessIterator - partial_sort_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + partial_sort_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last, @@ -2119,10 +2304,10 @@ constexpr bool is_sorted(ForwardIterator first, ForwardIterator last, Compare comp); template - bool is_sorted(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool is_sorted(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template - bool is_sorted(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool is_sorted(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Compare comp); @@ -2144,11 +2329,11 @@ Compare comp); template ForwardIterator - is_sorted_until(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + is_sorted_until(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template ForwardIterator - is_sorted_until(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + is_sorted_until(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Compare comp); @@ -2170,11 +2355,11 @@ constexpr void nth_element(RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last, Compare comp); template - void nth_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void nth_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last); template - void nth_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void nth_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last, Compare comp); @@ -2191,83 +2376,95 @@ } // \ref{alg.binary.search}, binary search - template + template::value_type> constexpr ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value); - template + template::value_type, + class Compare> constexpr ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); namespace ranges { - template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> constexpr I lower_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template<@\libconcept{forward_range}@ R, class T, class Proj = identity, + template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr borrowed_iterator_t lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); } - template + template::value_type> constexpr ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value); - template + template::value_type, + class Compare> constexpr ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); namespace ranges { - template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> constexpr I upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template<@\libconcept{forward_range}@ R, class T, class Proj = identity, + template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr borrowed_iterator_t upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); } - template + template::value_type> constexpr pair equal_range(ForwardIterator first, ForwardIterator last, const T& value); - template + template::value_type, + class Compare> constexpr pair equal_range(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); namespace ranges { - template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> Comp = ranges::less> constexpr subrange equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template<@\libconcept{forward_range}@ R, class T, class Proj = identity, + template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr borrowed_subrange_t equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {}); } - template + template::value_type> constexpr bool binary_search(ForwardIterator first, ForwardIterator last, const T& value); - template + template::value_type, + class Compare> constexpr bool binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); namespace ranges { - template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> constexpr bool binary_search(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template<@\libconcept{forward_range}@ R, class T, class Proj = identity, + template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr bool binary_search(R&& r, const T& value, Comp comp = {}, @@ -2278,7 +2475,7 @@ template constexpr bool is_partitioned(InputIterator first, InputIterator last, Predicate pred); template - bool is_partitioned(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool is_partitioned(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { @@ -2295,7 +2492,7 @@ ForwardIterator last, Predicate pred); template - ForwardIterator partition(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator partition(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Predicate pred); @@ -2313,12 +2510,12 @@ } template - constexpr BidirectionalIterator stable_partition(BidirectionalIterator first, + constexpr BidirectionalIterator stable_partition(BidirectionalIterator first, // hosted BidirectionalIterator last, Predicate pred); template - BidirectionalIterator stable_partition(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - BidirectionalIterator first, + BidirectionalIterator stable_partition(ExecutionPolicy&& exec, // hosted, + BidirectionalIterator first, // see \ref{algorithms.parallel.overloads} BidirectionalIterator last, Predicate pred); @@ -2326,11 +2523,13 @@ template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, @\libconcept{indirect_unary_predicate}@> Pred> requires @\libconcept{permutable}@ - constexpr subrange stable_partition(I first, S last, Pred pred, Proj proj = {}); + constexpr subrange stable_partition(I first, S last, Pred pred, // hosted + Proj proj = {}); template<@\libconcept{bidirectional_range}@ R, class Proj = identity, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> requires @\libconcept{permutable}@> - constexpr borrowed_subrange_t stable_partition(R&& r, Pred pred, Proj proj = {}); + constexpr borrowed_subrange_t stable_partition(R&& r, Pred pred, // hosted + Proj proj = {}); } template pair - partition_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + partition_copy(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, ForwardIterator1 out_true, ForwardIterator2 out_false, Predicate pred); @@ -2397,14 +2596,14 @@ template ForwardIterator - merge(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + merge(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template ForwardIterator - merge(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + merge(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); @@ -2429,20 +2628,20 @@ } template - constexpr void inplace_merge(BidirectionalIterator first, + constexpr void inplace_merge(BidirectionalIterator first, // hosted BidirectionalIterator middle, BidirectionalIterator last); template - constexpr void inplace_merge(BidirectionalIterator first, + constexpr void inplace_merge(BidirectionalIterator first, // hosted BidirectionalIterator middle, BidirectionalIterator last, Compare comp); template - void inplace_merge(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void inplace_merge(ExecutionPolicy&& exec, // hosted, see \ref{algorithms.parallel.overloads} BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last); template - void inplace_merge(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void inplace_merge(ExecutionPolicy&& exec, // hosted, see \ref{algorithms.parallel.overloads} BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last, Compare comp); @@ -2451,12 +2650,12 @@ template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@ - constexpr I inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {}); + constexpr I + inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {}); // hosted template<@\libconcept{bidirectional_range}@ R, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@, Comp, Proj> constexpr borrowed_iterator_t - inplace_merge(R&& r, iterator_t middle, Comp comp = {}, - Proj proj = {}); + inplace_merge(R&& r, iterator_t middle, Comp comp = {}, Proj proj = {}); // hosted } // \ref{alg.set.operations}, set operations @@ -2468,12 +2667,12 @@ InputIterator2 first2, InputIterator2 last2, Compare comp); template - bool includes(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool includes(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template - bool includes(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool includes(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, Compare comp); @@ -2500,20 +2699,20 @@ OutputIterator result); template constexpr OutputIterator - set_union(InputIterator1 first1, InputIterator1 last1, + set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); template ForwardIterator - set_union(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_union(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template ForwardIterator - set_union(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_union(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); @@ -2550,14 +2749,14 @@ template ForwardIterator - set_intersection(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_intersection(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template ForwardIterator - set_intersection(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_intersection(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); @@ -2594,14 +2793,14 @@ template ForwardIterator - set_difference(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_difference(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template ForwardIterator - set_difference(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_difference(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); @@ -2638,14 +2837,14 @@ template ForwardIterator - set_symmetric_difference(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_symmetric_difference(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template ForwardIterator - set_symmetric_difference(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + set_symmetric_difference(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); @@ -2750,10 +2949,10 @@ constexpr bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp); template - bool is_heap(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool is_heap(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last); template - bool is_heap(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + bool is_heap(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last, Compare comp); @@ -2775,11 +2974,11 @@ Compare comp); template RandomAccessIterator - is_heap_until(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + is_heap_until(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last); template RandomAccessIterator - is_heap_until(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + is_heap_until(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} RandomAccessIterator first, RandomAccessIterator last, Compare comp); @@ -2871,10 +3070,10 @@ constexpr ForwardIterator min_element(ForwardIterator first, ForwardIterator last, Compare comp); template - ForwardIterator min_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator min_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template - ForwardIterator min_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator min_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Compare comp); @@ -2894,10 +3093,10 @@ constexpr ForwardIterator max_element(ForwardIterator first, ForwardIterator last, Compare comp); template - ForwardIterator max_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator max_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template - ForwardIterator max_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator max_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Compare comp); @@ -2919,11 +3118,11 @@ minmax_element(ForwardIterator first, ForwardIterator last, Compare comp); template pair - minmax_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + minmax_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template pair - minmax_element(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + minmax_element(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, Compare comp); namespace ranges { @@ -2965,13 +3164,13 @@ Compare comp); template bool - lexicographical_compare(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + lexicographical_compare(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2); template bool - lexicographical_compare(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + lexicographical_compare(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, Compare comp); @@ -3362,10 +3561,11 @@ \indexlibraryglobal{contains}% \begin{itemdecl} -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {}); -template<@\libconcept{input_range}@ R, class T, class Proj = identity> +template<@\libconcept{input_range}@ R, class Proj = identity, class T = projected_value_t, Proj>> requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); \end{itemdecl} @@ -3642,10 +3842,11 @@ \indexlibraryglobal{find_if}% \indexlibraryglobal{find_if_not}% \begin{itemdecl} -template +template::value_type> constexpr InputIterator find(InputIterator first, InputIterator last, const T& value); -template +template::value_type> ForwardIterator find(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value); @@ -3664,10 +3865,11 @@ ForwardIterator first, ForwardIterator last, Predicate pred); -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr I ranges::find(I first, S last, const T& value, Proj proj = {}); -template<@\libconcept{input_range}@ R, class T, class Proj = identity> +template<@\libconcept{input_range}@ R, class Proj = identity, class T = projected_value_t, Proj>> requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr borrowed_iterator_t ranges::find(R&& r, const T& value, Proj proj = {}); @@ -3715,10 +3917,12 @@ \indexlibraryglobal{find_last}% \begin{itemdecl} -template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr subrange ranges::find_last(I first, S last, const T& value, Proj proj = {}); -template<@\libconcept{forward_range}@ R, class T, class Proj = identity> +template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr borrowed_subrange_t ranges::find_last(R&& r, const T& value, Proj proj = {}); template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, @@ -3912,7 +4116,7 @@ \pnum \complexity -At most \tcode{(last1-first1) * (last2-first2)} applications +At most \tcode{(last1 - first1) * (last2 - first2)} applications of the corresponding predicate and any projections. \end{itemdescr} @@ -3981,10 +4185,11 @@ \indexlibraryglobal{count}% \indexlibraryglobal{count_if}% \begin{itemdecl} -template +template::value_type> constexpr typename iterator_traits::difference_type count(InputIterator first, InputIterator last, const T& value); -template +template::value_type> typename iterator_traits::difference_type count(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value); @@ -3997,11 +4202,12 @@ count_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred); -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr iter_difference_t ranges::count(I first, S last, const T& value, Proj proj = {}); -template<@\libconcept{input_range}@ R, class T, class Proj = identity> +template<@\libconcept{input_range}@ R, class Proj = identity, class T = projected_value_t, Proj>> requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr range_difference_t ranges::count(R&& r, const T& value, Proj proj = {}); @@ -4350,7 +4556,7 @@ \pnum \complexity -No applications of the corresponding predicate and projections if: +No applications of the corresponding predicate and projections if \begin{itemize} \item for the first overload, @@ -4403,7 +4609,7 @@ \begin{itemdescr} \pnum \returns -The first iterator \tcode{i} in the range \range{first1}{last1 - (last2-first2)} +The first iterator \tcode{i} in the range \crange{first1}{last1 - (last2 - first2)} such that for every non-negative integer \tcode{n} less than \tcode{last2 - first2} the following corresponding conditions hold: @@ -4441,7 +4647,7 @@ \item \tcode{\{i, i + (last2 - first2)\}}, where \tcode{i} is - the first iterator in the range \range{first1}{last1 - (last2 - first2)} + the first iterator in the range \crange{first1}{last1 - (last2 - first2)} such that for every non-negative integer \tcode{n} less than \tcode{last2 - first2} the condition @@ -4461,23 +4667,25 @@ \indexlibraryglobal{search_n}% \begin{itemdecl} -template +template::value_type> constexpr ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, const T& value); -template +template::value_type> ForwardIterator search_n(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Size count, const T& value); -template::value_type, class BinaryPredicate> constexpr ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, const T& value, BinaryPredicate pred); -template::value_type, class BinaryPredicate> ForwardIterator search_n(ExecutionPolicy&& exec, @@ -4493,12 +4701,16 @@ The type \tcode{Size} is convertible to an integral type\iref{conv.integral,class.conv}. +\pnum +Let $E$ be \tcode{pred(*(i + n), value) != false} +for the overloads with a parameter \tcode{pred}, +and \tcode{*(i + n) == value} otherwise. + \pnum \returns -The first iterator \tcode{i} in the range \range{first}{last-count} +The first iterator \tcode{i} in the range \crange{first}{last - count} such that for every non-negative integer \tcode{n} less than \tcode{count} -the following corresponding conditions hold: -\tcode{*(i + n) == value, pred(*(i + n), value) != false}. +the condition $E$ is \tcode{true}. Returns \tcode{last} if no such iterator is found. \pnum @@ -4508,14 +4720,15 @@ \indexlibraryglobal{search_n}% \begin{itemdecl} -template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, - class Pred = ranges::equal_to, class Proj = identity> +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, + class Pred = ranges::equal_to, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirectly_comparable}@ constexpr subrange ranges::search_n(I first, S last, iter_difference_t count, const T& value, Pred pred = {}, Proj proj = {}); -template<@\libconcept{forward_range}@ R, class T, class Pred = ranges::equal_to, - class Proj = identity> +template<@\libconcept{forward_range}@ R, class Pred = ranges::equal_to, + class Proj = identity, class T = projected_value_t, Proj>> requires @\libconcept{indirectly_comparable}@, const T*, Pred, Proj> constexpr borrowed_subrange_t ranges::search_n(R&& r, range_difference_t count, @@ -4526,7 +4739,7 @@ \pnum \returns \tcode{\{i, i + count\}} -where \tcode{i} is the first iterator in the range \range{first}{last - count} +where \tcode{i} is the first iterator in the range \crange{first}{last - count} such that for every non-negative integer \tcode{n} less than \tcode{count}, the following condition holds: \tcode{invoke(pred, invoke(proj, *(i + n)), value)}. @@ -4626,7 +4839,8 @@ \returns \tcode{false} if $\tcode{N1} < \tcode{N2}$, otherwise \begin{codeblock} -ranges::equal(ranges::drop_view(ranges::ref_view(r1), N1 - N2), r2, pred, proj1, proj2) +ranges::equal(views::drop(ranges::ref_view(r1), N1 - static_cast(N2)), + r2, pred, proj1, proj2) \end{codeblock} \end{itemdescr} @@ -4634,9 +4848,11 @@ \indexlibraryglobal{fold_left}% \begin{itemdecl} -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, @\exposconcept{indirectly-binary-left-foldable}@ F> +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T = iter_value_t, + @\exposconcept{indirectly-binary-left-foldable}@ F> constexpr auto ranges::fold_left(I first, S last, T init, F f); -template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@> F> +template<@\libconcept{input_range}@ R, class T = range_value_t, + @\exposconcept{indirectly-binary-left-foldable}@> F> constexpr auto ranges::fold_left(R&& r, T init, F f); \end{itemdecl} @@ -4669,10 +4885,10 @@ \indexlibraryglobal{fold_right}% \begin{itemdecl} -template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, +template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, class T = iter_value_t, @\exposconcept{indirectly-binary-right-foldable}@ F> constexpr auto ranges::fold_right(I first, S last, T init, F f); -template<@\libconcept{bidirectional_range}@ R, class T, +template<@\libconcept{bidirectional_range}@ R, class T = range_value_t, @\exposconcept{indirectly-binary-right-foldable}@> F> constexpr auto ranges::fold_right(R&& r, T init, F f); \end{itemdecl} @@ -4724,10 +4940,11 @@ \indexlibraryglobal{fold_left_with_iter}% \begin{itemdecl} -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T = iter_value_t, @\exposconcept{indirectly-binary-left-foldable}@ F> constexpr @\seebelow@ ranges::fold_left_with_iter(I first, S last, T init, F f); -template<@\libconcept{input_range}@ R, class T, @\exposconcept{indirectly-binary-left-foldable}@> F> +template<@\libconcept{input_range}@ R, class T = range_value_t, + @\exposconcept{indirectly-binary-left-foldable}@> F> constexpr @\seebelow@ ranges::fold_left_with_iter(R&& r, T init, F f); \end{itemdecl} @@ -4845,7 +5062,7 @@ \indexlibraryglobal{copy}% \begin{itemdecl} template - ForwardIterator2 copy(ExecutionPolicy&& policy, + ForwardIterator2 copy(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); \end{itemdecl} @@ -5108,7 +5325,7 @@ \indexlibrary{\idxcode{move}!algorithm}% \begin{itemdecl} template - ForwardIterator2 move(ExecutionPolicy&& policy, + ForwardIterator2 move(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); \end{itemdecl} @@ -5331,14 +5548,14 @@ @\libconcept{weakly_incrementable}@ O, @\libconcept{copy_constructible}@ F, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, - projected>> + 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<@\libconcept{input_range}@ R1, @\libconcept{input_range}@ R2, @\libconcept{weakly_incrementable}@ O, @\libconcept{copy_constructible}@ F, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, Proj1>, - projected, Proj2>>> + projected, Proj2>>> constexpr ranges::binary_transform_result, borrowed_iterator_t, O> ranges::transform(R1&& r1, R2&& r2, O result, F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -5423,37 +5640,43 @@ \indexlibraryglobal{replace}% \indexlibraryglobal{replace_if}% \begin{itemdecl} -template +template::value_type> constexpr void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value); -template +template::value_type> void replace(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value); -template +template::value_type> constexpr void replace_if(ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value); -template +template::value_type> void replace_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value); -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T1, class T2, class Proj = identity> +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T1 = projected_value_t, class T2 = T1> requires @\libconcept{indirectly_writable}@ && @\libconcept{indirect_binary_predicate}@, const T1*> constexpr I ranges::replace(I first, S last, const T1& old_value, const T2& new_value, Proj proj = {}); -template<@\libconcept{input_range}@ R, class T1, class T2, class Proj = identity> +template<@\libconcept{input_range}@ R, class Proj = identity, + class T1 = projected_value_t, Proj>, class T2 = T1> requires @\libconcept{indirectly_writable}@, const T2&> && @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> constexpr borrowed_iterator_t ranges::replace(R&& r, const T1& old_value, const T2& new_value, Proj proj = {}); -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_unary_predicate}@> Pred> requires @\libconcept{indirectly_writable}@ constexpr I ranges::replace_if(I first, S last, Pred pred, const T& new_value, Proj proj = {}); -template<@\libconcept{input_range}@ R, class T, class Proj = identity, +template<@\libconcept{input_range}@ R, class Proj = identity, class T = projected_value_t, Proj>, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> requires @\libconcept{indirectly_writable}@, const T&> constexpr borrowed_iterator_t @@ -5519,30 +5742,32 @@ ForwardIterator2 result, Predicate pred, const T& new_value); -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T1, class T2, @\libconcept{output_iterator}@ O, - class Proj = identity> +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class O, + class Proj = identity, class T1 = projected_value_t, class T2 = iter_value_t> requires @\libconcept{indirectly_copyable}@ && - @\libconcept{indirect_binary_predicate}@, const T1*> + @\libconcept{indirect_binary_predicate}@, const T1*> && + @\libconcept{output_iterator}@ 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<@\libconcept{input_range}@ R, class T1, class T2, @\libconcept{output_iterator}@ O, - class Proj = identity> +template<@\libconcept{input_range}@ R, class O, class Proj = identity, + class T1 = projected_value_t, Proj>, class T2 = iter_value_t> requires @\libconcept{indirectly_copyable}@, O> && @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> + && @\libconcept{output_iterator}@ constexpr ranges::replace_copy_result, O> ranges::replace_copy(R&& r, O result, const T1& old_value, const T2& new_value, Proj proj = {}); -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, @\libconcept{output_iterator}@ O, +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S,class O, class T = iter_value_t, class Proj = identity, @\libconcept{indirect_unary_predicate}@> Pred> - requires @\libconcept{indirectly_copyable}@ + requires @\libconcept{indirectly_copyable}@ && @\libconcept{output_iterator}@ 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<@\libconcept{input_range}@ R, class T, @\libconcept{output_iterator}@ O, class Proj = identity, +template<@\libconcept{input_range}@ R, class O, class T = iter_value_t, class Proj = identity, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> - requires @\libconcept{indirectly_copyable}@, O> + requires @\libconcept{indirectly_copyable}@, O> && @\libconcept{output_iterator}@ constexpr ranges::replace_copy_if_result, O> ranges::replace_copy_if(R&& r, O result, Pred pred, const T& new_value, Proj proj = {}); @@ -5605,23 +5830,28 @@ \indexlibraryglobal{fill}% \indexlibraryglobal{fill_n}% \begin{itemdecl} -template +template::value_type> constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value); -template +template::value_type> void fill(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value); -template +template::value_type> constexpr OutputIterator fill_n(OutputIterator first, Size n, const T& value); -template +template::value_type> ForwardIterator fill_n(ExecutionPolicy&& exec, ForwardIterator first, Size n, const T& value); -template O, @\libconcept{sentinel_for}@ S> +template S, class T = iter_value_t> + requires @\libconcept{output_iterator}@ constexpr O ranges::fill(O first, S last, const T& value); -template R> +template> + requires @\libconcept{output_range}@ constexpr borrowed_iterator_t ranges::fill(R&& r, const T& value); -template O> +template> + requires @\libconcept{output_iterator}@ constexpr O ranges::fill_n(O first, iter_difference_t n, const T& value); \end{itemdecl} @@ -5710,10 +5940,11 @@ \indexlibraryglobal{remove}% \indexlibraryglobal{remove_if}% \begin{itemdecl} -template +template::value_type> constexpr ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value); -template +template::value_type> ForwardIterator remove(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value); @@ -5726,10 +5957,12 @@ ForwardIterator first, ForwardIterator last, Predicate pred); -template<@\libconcept{permutable}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> +template<@\libconcept{permutable}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t> requires @\libconcept{indirect_binary_predicate}@, const T*> constexpr subrange ranges::remove(I first, S last, const T& value, Proj proj = {}); -template<@\libconcept{forward_range}@ R, class T, class Proj = identity> +template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{permutable}@> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr borrowed_subrange_t @@ -5795,12 +6028,13 @@ \indexlibraryglobal{remove_copy}% \indexlibraryglobal{remove_copy_if}% \begin{itemdecl} -template +template::value_type> constexpr OutputIterator remove_copy(InputIterator first, InputIterator last, OutputIterator result, const T& value); template + class T = iterator_traits::value_type> ForwardIterator2 remove_copy(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, @@ -5817,13 +6051,14 @@ ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, Predicate pred); -template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, @\libconcept{weakly_incrementable}@ O, class T, - class Proj = identity> +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, @\libconcept{weakly_incrementable}@ O, + class Proj = identity, class T = projected_value_t> requires @\libconcept{indirectly_copyable}@ && @\libconcept{indirect_binary_predicate}@, const T*> constexpr ranges::remove_copy_result ranges::remove_copy(I first, S last, O result, const T& value, Proj proj = {}); -template<@\libconcept{input_range}@ R, @\libconcept{weakly_incrementable}@ O, class T, class Proj = identity> +template<@\libconcept{input_range}@ R, @\libconcept{weakly_incrementable}@ O, class Proj = identity, + class T = projected_value_t, Proj>> requires @\libconcept{indirectly_copyable}@, O> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> constexpr ranges::remove_copy_result, O> @@ -6028,7 +6263,7 @@ \expects \begin{itemize} \item - The ranges \range{first}{last} and \range{result}{result+(last-first)} + The ranges \range{first}{last} and \range{result}{result + (last - first)} do not overlap. \item For the overloads in namespace \tcode{std}: @@ -6529,7 +6764,7 @@ from position \tcode{first + i} into position \tcode{first + n + i} for each non-negative integer \tcode{i < (last - first) - n}. Does so in order starting -from \tcode{i = (last - first) - n - 1} and proceeding to \tcode{i = 0} if: +from \tcode{i = (last - first) - n - 1} and proceeding to \tcode{i = 0} if \begin{itemize} \item for the overload in namespace \tcode{std} @@ -7195,21 +7430,24 @@ \indexlibraryglobal{lower_bound}% \begin{itemdecl} -template +template::value_type> constexpr ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value); -template +template::value_type, + class Compare> constexpr ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> constexpr I ranges::lower_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template<@\libconcept{forward_range}@ R, class T, class Proj = identity, +template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr borrowed_iterator_t @@ -7243,20 +7481,23 @@ \indexlibraryglobal{upper_bound}% \begin{itemdecl} -template +template::value_type> constexpr ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value); -template +template::value_type, + class Compare> constexpr ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> constexpr I ranges::upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template<@\libconcept{forward_range}@ R, class T, class Proj = identity, +template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr borrowed_iterator_t @@ -7290,22 +7531,25 @@ \indexlibraryglobal{equal_range}% \begin{itemdecl} -template +template::value_type> constexpr pair equal_range(ForwardIterator first, ForwardIterator last, const T& value); -template +template::value_type, + class Compare> constexpr pair equal_range(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> constexpr subrange ranges::equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template<@\libconcept{forward_range}@ R, class T, class Proj = identity, +template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr borrowed_subrange_t @@ -7324,7 +7568,7 @@ are partitioned with respect to the expressions \tcode{bool(invoke(comp, invoke(proj, e), value))} and \tcode{!bool(invoke(comp, value, invoke(proj, e)))}. -Also, for all elements \tcode{e} of \tcode{[first, last)}, +Also, for all elements \tcode{e} of \range{first}{last}, \tcode{bool(comp(e, value))} implies \tcode{!bool(comp(\brk{}value, e))} for the overloads in namespace \tcode{std}. @@ -7355,21 +7599,24 @@ \indexlibraryglobal{binary_search}% \begin{itemdecl} -template +template::value_type> constexpr bool binary_search(ForwardIterator first, ForwardIterator last, const T& value); -template +template::value_type, + class Compare> constexpr bool binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity, +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + class T = projected_value_t, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> constexpr bool ranges::binary_search(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template<@\libconcept{forward_range}@ R, class T, class Proj = identity, +template<@\libconcept{forward_range}@ R, class Proj = identity, + class T = projected_value_t, Proj>, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> constexpr bool ranges::binary_search(R&& r, const T& value, Comp comp = {}, @@ -7388,7 +7635,7 @@ are partitioned with respect to the expressions \tcode{bool(invoke(comp, invoke(proj, e), value))} and \tcode{!bool(invoke(comp, value, invoke(proj, e)))}. -Also, for all elements \tcode{e} of \tcode{[first, last)}, +Also, for all elements \tcode{e} of \range{first}{last}, \tcode{bool(comp(e, value))} implies \tcode{!bool(comp(\brk{}value, e))} for the overloads in namespace \tcode{std}. @@ -7854,7 +8101,7 @@ \begin{itemize} \item For the overloads with no \tcode{ExecutionPolicy}, and - if enough additional memory is available, exactly $N - 1$ comparisons. + if enough additional memory is available, at most $N - 1$ comparisons. \item Otherwise, \bigoh{N \log N} comparisons. \end{itemize} @@ -9209,7 +9456,7 @@ \tcode{ranges::lexicographical_compare(I1, S1, I2, S2, Comp, Proj1, Proj2)} can be implemented as: \begin{codeblock} -for ( ; first1 != last1 && first2 != last2 ; ++first1, (void) ++first2) { +for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) { if (invoke(comp, invoke(proj1, *first1), invoke(proj2, *first2))) return true; if (invoke(comp, invoke(proj2, *first2), invoke(proj1, *first1))) return false; } @@ -9397,6 +9644,7 @@ \indexheader{numeric}% \begin{codeblock} +// mostly freestanding namespace std { // \ref{accumulate}, accumulate template @@ -9416,13 +9664,13 @@ BinaryOperation binary_op); template typename iterator_traits::value_type - reduce(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + reduce(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last); template - T reduce(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + T reduce(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, T init); template - T reduce(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + T reduce(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, T init, BinaryOperation binary_op); // \ref{inner.product}, inner product @@ -9450,19 +9698,19 @@ BinaryOperation binary_op, UnaryOperation unary_op); template - T transform_reduce(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + T transform_reduce(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, T init); template - T transform_reduce(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + T transform_reduce(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2); template - T transform_reduce(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + T transform_reduce(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, T init, BinaryOperation binary_op, UnaryOperation unary_op); @@ -9487,13 +9735,13 @@ OutputIterator result, T init, BinaryOperation binary_op); template ForwardIterator2 - exclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + exclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, T init); template ForwardIterator2 - exclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + exclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, T init, BinaryOperation binary_op); @@ -9512,19 +9760,19 @@ OutputIterator result, BinaryOperation binary_op, T init); template ForwardIterator2 - inclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + inclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); template ForwardIterator2 - inclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + inclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op); template ForwardIterator2 - inclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + inclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op, T init); @@ -9538,7 +9786,7 @@ template ForwardIterator2 - transform_exclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + transform_exclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, T init, BinaryOperation binary_op, UnaryOperation unary_op); @@ -9559,14 +9807,14 @@ template ForwardIterator2 - transform_inclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + transform_inclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op, UnaryOperation unary_op); template ForwardIterator2 - transform_inclusive_scan(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + transform_inclusive_scan(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op, UnaryOperation unary_op, T init); @@ -9582,13 +9830,13 @@ OutputIterator result, BinaryOperation binary_op); template ForwardIterator2 - adjacent_difference(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + adjacent_difference(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); template ForwardIterator2 - adjacent_difference(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + adjacent_difference(ExecutionPolicy&& exec, // freestanding-deleted, see \ref{algorithms.parallel.overloads} ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op); @@ -9621,6 +9869,18 @@ constexpr T midpoint(T a, T b) noexcept; template constexpr T* midpoint(T* a, T* b); + + // \ref{numeric.sat}, saturation arithmetic + template + constexpr T add_sat(T x, T y) noexcept; + template + constexpr T sub_sat(T x, T y) noexcept; + template + constexpr T mul_sat(T x, T y) noexcept; + template + constexpr T div_sat(T x, T y) noexcept; + template + constexpr T saturate_cast(U x) noexcept; } \end{codeblock} @@ -10562,7 +10822,7 @@ \pnum For the overloads with an \tcode{ExecutionPolicy} and a non-empty range, performs \tcode{*result = *first}. -Then, for every \tcode{d} in \tcode{[1, last - first - 1]}, +Then, for every \tcode{d} in \crange{1}{last - first - 1}, performs \tcode{*(result + d) = binary_op(*(first + d), *(first + (d - 1)))}. \pnum @@ -10755,6 +11015,117 @@ where the result of the division is truncated towards zero. \end{itemdescr} +\rSec2[numeric.sat]{Saturation arithmetic} + +\rSec3[numeric.sat.func]{Arithmetic functions} + +\pnum +In the following descriptions, an arithmetic operation +is performed as a mathematical operation with infinite range and then +it is determined whether the mathematical result fits into the result type. + +\indexlibraryglobal{add_sat}% +\begin{itemdecl} +template + constexpr T add_sat(T x, T y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a signed or unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +If $\tcode{x} + \tcode{y}$ is representable as a value of type \tcode{T}, $\tcode{x} + \tcode{y}$; +otherwise, either the largest or smallest representable value of type \tcode{T}, +whichever is closer to the value of $\tcode{x} + \tcode{y}$. +\end{itemdescr} + +\indexlibraryglobal{sub_sat}% +\begin{itemdecl} +template + constexpr T sub_sat(T x, T y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a signed or unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +If $\tcode{x} - \tcode{y}$ is representable as a value of type \tcode{T}, $\tcode{x} - \tcode{y}$; +otherwise, either the largest or smallest representable value of type \tcode{T}, +whichever is closer to the value of $\tcode{x} - \tcode{y}$. +\end{itemdescr} + +\indexlibraryglobal{mul_sat}% +\begin{itemdecl} +template + constexpr T mul_sat(T x, T y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a signed or unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +If $\tcode{x} \times \tcode{y}$ is representable as a value of type \tcode{T}, $\tcode{x} \times \tcode{y}$; +otherwise, either the largest or smallest representable value of type \tcode{T}, +whichever is closer to the value of $\tcode{x} \times \tcode{y}$. +\end{itemdescr} + +\indexlibraryglobal{div_sat}% +\begin{itemdecl} +template + constexpr T div_sat(T x, T y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a signed or unsigned integer type\iref{basic.fundamental}. + +\pnum +\expects +\tcode{y != 0} is \tcode{true}. + +\pnum +\returns +If \tcode{T} is a signed integer type +and \tcode{x == numeric_limits::min() \&\& y == -1} is \tcode{true}, +\tcode{numeric_limits::max()}, otherwise, \tcode{x / y}. + +\pnum +\remarks +A function call expression +that violates the precondition in the \Fundescx{Preconditions} element +is not a core constant expression\iref{expr.const}. +\end{itemdescr} + +\rSec3[numeric.sat.cast]{Casting} + +\indexlibraryglobal{saturate_cast}% +\begin{itemdecl} +template + constexpr R saturate_cast(T x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{R} and \tcode{T} are signed or unsigned integer types\iref{basic.fundamental}. + +\pnum +\returns +If \tcode{x} is representable as a value of type \tcode{R}, \tcode{x}; +otherwise, either the largest or smallest representable value of type \tcode{R}, +whichever is closer to the value of \tcode{x}. +\end{itemdescr} + \rSec1[specialized.algorithms]{Specialized \tcode{} algorithms} \rSec2[specialized.algorithms.general]{General} @@ -10770,15 +11141,31 @@ are destroyed in an unspecified order before allowing the exception to propagate. +\pnum +\begin{note} +When new objects are created by +the algorithms specified in \ref{specialized.algorithms}, +the lifetime ends for any existing objects +(including potentially-overlapping subobjects \ref{intro.object}) +in storage that is reused \ref{basic.life}. +\end{note} + \pnum Some algorithms specified in \ref{specialized.algorithms} -make use of the exposition-only function template -\tcode{\placeholdernc{voidify}}: +make use of the following exposition-only function templates: \begin{codeblock} template constexpr void* @\placeholdernc{voidify}@(T& obj) noexcept { return addressof(obj); } + +template + decltype(auto) @\exposid{deref-move}@(I& it) { + if constexpr (is_lvalue_reference_v) + return std::move(*it); + else + return *it; + } \end{codeblock} \rSec2[special.mem.concepts]{Special memory concepts} @@ -10872,7 +11259,8 @@ \indexlibraryglobal{uninitialized_default_construct}% \begin{itemdecl} template - void uninitialized_default_construct(NoThrowForwardIterator first, NoThrowForwardIterator last); + constexpr void uninitialized_default_construct(NoThrowForwardIterator first, + NoThrowForwardIterator last); \end{itemdecl} \begin{itemdescr} @@ -10891,10 +11279,10 @@ namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> - I uninitialized_default_construct(I first, S last); + constexpr I uninitialized_default_construct(I first, S last); template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> - borrowed_iterator_t uninitialized_default_construct(R&& r); + constexpr borrowed_iterator_t uninitialized_default_construct(R&& r); } \end{itemdecl} @@ -10912,7 +11300,8 @@ \indexlibraryglobal{uninitialized_default_construct_n}% \begin{itemdecl} template - NoThrowForwardIterator uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); + constexpr NoThrowForwardIterator + uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); \end{itemdecl} \begin{itemdescr} @@ -10932,7 +11321,7 @@ namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> - I uninitialized_default_construct_n(I first, iter_difference_t n); + constexpr I uninitialized_default_construct_n(I first, iter_difference_t n); } \end{itemdecl} @@ -10951,7 +11340,8 @@ \indexlibraryglobal{uninitialized_value_construct}% \begin{itemdecl} template - void uninitialized_value_construct(NoThrowForwardIterator first, NoThrowForwardIterator last); + constexpr void uninitialized_value_construct(NoThrowForwardIterator first, + NoThrowForwardIterator last); \end{itemdecl} \begin{itemdescr} @@ -10970,10 +11360,10 @@ namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> - I uninitialized_value_construct(I first, S last); + constexpr I uninitialized_value_construct(I first, S last); template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> - borrowed_iterator_t uninitialized_value_construct(R&& r); + constexpr borrowed_iterator_t uninitialized_value_construct(R&& r); } \end{itemdecl} @@ -10991,7 +11381,8 @@ \indexlibraryglobal{uninitialized_value_construct_n}% \begin{itemdecl} template - NoThrowForwardIterator uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); + constexpr NoThrowForwardIterator + uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); \end{itemdecl} \begin{itemdescr} @@ -11011,7 +11402,7 @@ namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> - I uninitialized_value_construct_n(I first, iter_difference_t n); + constexpr I uninitialized_value_construct_n(I first, iter_difference_t n); } \end{itemdecl} @@ -11030,8 +11421,8 @@ \indexlibraryglobal{uninitialized_copy}% \begin{itemdecl} template - NoThrowForwardIterator uninitialized_copy(InputIterator first, InputIterator last, - NoThrowForwardIterator result); + constexpr NoThrowForwardIterator uninitialized_copy(InputIterator first, InputIterator last, + NoThrowForwardIterator result); \end{itemdecl} \begin{itemdescr} @@ -11043,7 +11434,7 @@ \effects Equivalent to: \begin{codeblock} -for (; first != last; ++result, (void) ++first) +for (; first != last; ++result, (void)++first) ::new (@\placeholdernc{voidify}@(*result)) typename iterator_traits::value_type(*first); \end{codeblock} @@ -11059,11 +11450,11 @@ template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_reference_t> - uninitialized_copy_result + constexpr uninitialized_copy_result uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_reference_t> - uninitialized_copy_result, borrowed_iterator_t> + constexpr uninitialized_copy_result, borrowed_iterator_t> uninitialized_copy(IR&& in_range, OR&& out_range); } \end{itemdecl} @@ -11086,8 +11477,8 @@ \indexlibraryglobal{uninitialized_copy_n}% \begin{itemdecl} template - NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, - NoThrowForwardIterator result); + constexpr NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, + NoThrowForwardIterator result); \end{itemdecl} \begin{itemdescr} @@ -11099,7 +11490,7 @@ \effects Equivalent to: \begin{codeblock} -for ( ; n > 0; ++result, (void) ++first, --n) +for (; n > 0; ++result, (void)++first, --n) ::new (@\placeholdernc{voidify}@(*result)) typename iterator_traits::value_type(*first); \end{codeblock} @@ -11114,7 +11505,7 @@ namespace ranges { template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_reference_t> - uninitialized_copy_n_result + constexpr uninitialized_copy_n_result uninitialized_copy_n(I ifirst, iter_difference_t n, O ofirst, S olast); } \end{itemdecl} @@ -11140,8 +11531,8 @@ \indexlibraryglobal{uninitialized_move}% \begin{itemdecl} template - NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, - NoThrowForwardIterator result); + constexpr NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, + NoThrowForwardIterator result); \end{itemdecl} \begin{itemdescr} @@ -11155,7 +11546,7 @@ \begin{codeblock} for (; first != last; (void)++result, ++first) ::new (@\placeholdernc{voidify}@(*result)) - typename iterator_traits::value_type(std::move(*first)); + typename iterator_traits::value_type(@\exposid{deref-move}@(first)); return result; \end{codeblock} \end{itemdescr} @@ -11166,11 +11557,11 @@ template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> - uninitialized_move_result + constexpr uninitialized_move_result uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_rvalue_reference_t> - uninitialized_move_result, borrowed_iterator_t> + constexpr uninitialized_move_result, borrowed_iterator_t> uninitialized_move(IR&& in_range, OR&& out_range); } \end{itemdecl} @@ -11200,7 +11591,7 @@ \indexlibraryglobal{uninitialized_move_n}% \begin{itemdecl} template - pair + constexpr pair uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result); \end{itemdecl} @@ -11213,9 +11604,9 @@ \effects Equivalent to: \begin{codeblock} -for (; n > 0; ++result, (void) ++first, --n) +for (; n > 0; ++result, (void)++first, --n) ::new (@\placeholdernc{voidify}@(*result)) - typename iterator_traits::value_type(std::move(*first)); + typename iterator_traits::value_type(@\exposid{deref-move}@(first)); return {first, result}; \end{codeblock} \end{itemdescr} @@ -11225,7 +11616,7 @@ namespace ranges { template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> - uninitialized_move_n_result + constexpr uninitialized_move_n_result uninitialized_move_n(I ifirst, iter_difference_t n, O ofirst, S olast); } \end{itemdecl} @@ -11257,7 +11648,8 @@ \indexlibraryglobal{uninitialized_fill}% \begin{itemdecl} template - void uninitialized_fill(NoThrowForwardIterator first, NoThrowForwardIterator last, const T& x); + constexpr void uninitialized_fill(NoThrowForwardIterator first, + NoThrowForwardIterator last, const T& x); \end{itemdecl} \begin{itemdescr} @@ -11276,10 +11668,10 @@ namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T> requires @\libconcept{constructible_from}@, const T&> - I uninitialized_fill(I first, S last, const T& x); + constexpr I uninitialized_fill(I first, S last, const T& x); template<@\exposconcept{nothrow-forward-range}@ R, class T> requires @\libconcept{constructible_from}@, const T&> - borrowed_iterator_t uninitialized_fill(R&& r, const T& x); + constexpr borrowed_iterator_t uninitialized_fill(R&& r, const T& x); } \end{itemdecl} @@ -11297,7 +11689,8 @@ \indexlibraryglobal{uninitialized_fill_n}% \begin{itemdecl} template - NoThrowForwardIterator uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); + constexpr NoThrowForwardIterator + uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); \end{itemdecl} \begin{itemdescr} @@ -11317,7 +11710,7 @@ namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, class T> requires @\libconcept{constructible_from}@, const T&> - I uninitialized_fill_n(I first, iter_difference_t n, const T& x); + constexpr I uninitialized_fill_n(I first, iter_difference_t n, const T& x); } \end{itemdecl} @@ -11346,14 +11739,22 @@ \begin{itemdescr} \pnum \constraints -The expression \tcode{::new (declval()) T(declval()...)} +\tcode{is_unbounded_array_v} is \tcode{false}. +The expression \tcode{::new (declval()) T(\linebreak{}declval()...)} is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand}. +\pnum +\mandates +If \tcode{is_array_v} is \tcode{true}, \tcode{sizeof...(Args)} is zero. + \pnum \effects Equivalent to: \begin{codeblock} -return ::new (@\placeholdernc{voidify}@(*location)) T(std::forward(args)...); +if constexpr (is_array_v) + return ::new (@\placeholdernc{voidify}@(*location)) T[1](); +else + return ::new (@\placeholdernc{voidify}@(*location)) T(std::forward(args)...); \end{codeblock} \end{itemdescr} @@ -11454,6 +11855,144 @@ \end{codeblock} \end{itemdescr} +\rSec1[alg.rand]{Specialized \tcode{} algorithms} + +\rSec2[alg.rand.general]{General} + +\pnum +The contents specified in \ref{alg.rand} +are declared in the header \libheaderrefx{random}{rand.synopsis}. + +\rSec2[alg.rand.generate]{\tcode{generate_random}} + +\indexlibraryglobal{generate_random}% +\begin{itemdecl} +template + requires @\libconcept{output_range}@> && @\libconcept{uniform_random_bit_generator}@> +constexpr borrowed_iterator_t ranges::generate_random(R&& r, G&& g); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +Calls \tcode{g.generate_random(std::forward(r))} +if this expression is well-formed. +\item +Otherwise, if \tcode{R} models \libconcept{sized_range}, +fills \tcode{r} with \tcode{ranges::size(r)} values of +type \tcode{invoke_result_t} by performing +an unspecified number of invocations of +the form \tcode{g()} or \tcode{g.generate_random(s)}, +if such an expression is well-formed for a value \tcode{N} and +an object \tcode{s} of type \tcode{span, N>}. +\begin{note} +Values of \tcode{N} can differ between invocations. +\end{note} +\item +Otherwise, calls \tcode{ranges::generate(std::forward(r), ref(g))}. +\end{itemize} + +\pnum +\returns +\tcode{ranges::end(r)}. + +\pnum +\remarks +The effects of \tcode{generate_random(r, g)} shall be equivalent to +\tcode{ranges::generate(std::for\-ward(r), ref(g))}. +\begin{note} +This implies that \tcode{g.generate_random(a)} fills \tcode{a} +with the same values as produced by invocation of \tcode{g()}. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{generate_random}% +\begin{itemdecl} +template> O, @\libconcept{sentinel_for}@ S> + requires @\libconcept{uniform_random_bit_generator}@> +constexpr O ranges::generate_random(O first, S last, G&& g); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return generate_random(subrange(std::move(first), last), g); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{generate_random}% +\begin{itemdecl} +template + requires @\libconcept{output_range}@> && @\libconcept{invocable}@ && + @\libconcept{uniform_random_bit_generator}@> && + is_arithmetic_v> +constexpr borrowed_iterator_t ranges::generate_random(R&& r, G&& g, D&& d); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +Calls \tcode{d.generate_random(std::forward(r), g)} +if this expression is well-formed. +\item +Otherwise, if \tcode{R} models \libconcept{sized_range}, +fills \tcode{r} with \tcode{ranges::size(r)} values of +type \tcode{invoke_result_t} +by performing an unspecified number of invocations of +the form \tcode{invoke(d, g)} or \tcode{d.generate_random(s, g)}, +if such an expression is well-formed +for a value \tcode{N} and +an object \tcode{s} of type \tcode{span, N>}. +\begin{note} +Values of N can differ between invocations. +\end{note} +\item +Otherwise, calls +\begin{codeblock} +ranges::generate(std::forward(r), [&d, &g] { return invoke(d, g); }); +\end{codeblock} +\end{itemize} + +\pnum +\returns +\tcode{ranges::end(r)}. + +\pnum +\remarks +The effects of \tcode{generate_random(r, g, d)} shall be equivalent to +\begin{codeblock} +ranges::generate(std::forward(r), [&d, &g] { return invoke(d, g); }) +\end{codeblock} +\begin{note} +This implies that \tcode{d.generate_random(a, g)} +fills \tcode{a} with the values with the same random distribution +as produced by invocation of \tcode{invoke(d, g)}. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{generate_random}% +\begin{itemdecl} +template> O, @\libconcept{sentinel_for}@ S> + requires @\libconcept{invocable}@ && @\libconcept{uniform_random_bit_generator}@> && + is_arithmetic_v> +constexpr O ranges::generate_random(O first, S last, G&& g, D&& d); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return generate_random(subrange(std::move(first), last), g, d); +\end{codeblock} +\end{itemdescr} + \rSec1[alg.c.library]{C library algorithms} \pnum diff --git a/source/assets/iso-logo-caution.png b/source/assets/iso-logo-caution.png new file mode 100644 index 0000000000..49b12792b8 Binary files /dev/null and b/source/assets/iso-logo-caution.png differ diff --git a/source/back.tex b/source/back.tex index 1107b0c2b4..7cd2714e9f 100644 --- a/source/back.tex +++ b/source/back.tex @@ -1,51 +1,96 @@ %!TEX root = std.tex -\chapter{Bibliography} +\renewcommand{\leftmark}{\bibname} -\begin{itemize} -\renewcommand{\labelitemi}{---} +\begin{thebibliography}{99} % ISO documents in numerical order. -\item +\bibitem{iso4217} ISO 4217:2015, \doccite{Codes for the representation of currencies} -\item +\bibitem{iso10967-1} ISO/IEC 10967-1:2012, \doccite{Information technology --- Language independent arithmetic --- Part 1: Integer and floating point arithmetic} -\item +\bibitem{iso14882:2023} + ISO/IEC 14882:2023, + \doccite{Programming Languages --- \Cpp{}} +\bibitem{iso14882:2020} + ISO/IEC 14882:2020, + \doccite{Programming Languages --- \Cpp{}} +\bibitem{iso14882:2017} + ISO/IEC 14882:2017, + \doccite{Programming Languages --- \Cpp{}} +\bibitem{iso14882:2014} + ISO/IEC 14882:2014, + \doccite{Information technology --- Programming Languages --- \Cpp{}} +\bibitem{iso14882:2011} + ISO/IEC 14882:2011, + \doccite{Information technology --- Programming Languages --- \Cpp{}} +\bibitem{iso14882:2003} + ISO/IEC 14882:2003, + \doccite{Programming Languages --- \Cpp{}} +\bibitem{iso18661-3} ISO/IEC TS 18661-3:2015, \doccite{Information Technology --- Programming languages, their environments, and system software interfaces --- Floating-point extensions for C --- Part 3: Interchange and extended types} % Other international standards. -\item +\bibitem{iana-charset} IANA Character Sets Database. Available from:\newline \url{https://www.iana.org/assignments/character-sets/}, 2021-04-01 -\item +\bibitem{iana-tz} IANA Time Zone Database. Available from: \url{https://www.iana.org/time-zones} -\item +\bibitem{unicode-charmap} Unicode Character Mapping Markup Language [online]. Edited by Mark Davis and Markus Scherer. Revision 5.0.1; 2017-05-31 - Available from: \url{http://www.unicode.org/reports/tr22/tr22-8.html} + Available from: \url{https://www.unicode.org/reports/tr22/tr22-8.html} % Literature references. -\item +\bibitem{cpp-r} Bjarne Stroustrup, \doccite{The \Cpp{} Programming Language, second edition}, Chapter R\@. Addison-Wesley Publishing Company, ISBN 0-201-53992-6, copyright \copyright 1991 AT\&T -\item - Brian W.\ Kernighan and Dennis M. Ritchie, +\bibitem{kr} + Brian W.\ Kernighan and Dennis M.\ Ritchie, \doccite{The C Programming Language}, Appendix A\@. Prentice-Hall, 1978, ISBN 0-13-110163-3, copyright \copyright 1978 AT\&T -\item - P.J.\ Plauger, +\bibitem{cpp-lib} + P.\,J.\ Plauger, \doccite{The Draft Standard \Cpp{} Library}. - Prentice-Hall, ISBN 0-13-117003-1, copyright \copyright 1995 P.J.\ Plauger -\end{itemize} - -The arithmetic specification described in ISO/IEC 10967-1:2012 is -called \defn{LIA-1} in this document. + Prentice-Hall, ISBN 0-13-117003-1, copyright \copyright 1995 P.\,J.\ Plauger +\bibitem{linalg-stable} + J.\ Demmel, I.\ Dumitriu, and O.\ Holtz, + \doccite{Fast linear algebra is stable}, + Numerische Mathematik 108 (59--91), 2007. +\bibitem{blas1} + C.\,L.\ Lawson, R.\,J.\ Hanson, D.\ Kincaid, and F.\,T.\ Krogh, + \doccite{Basic linear algebra subprograms for Fortran usage}. + ACM Trans.\ Math.\ Soft., Vol.\ 5, pp.\ 308--323, 1979. +\bibitem{blas2} + Jack J.\ Dongarra, Jeremy Du Croz, Sven Hammarling, and Richard J.\ Hanson, + \doccite{An Extended Set of FORTRAN Basic Linear Algebra Subprograms}. + ACM Trans.\ Math.\ Soft., Vol.\ 14, No.\ 1, pp.\ 1--17, Mar.\ 1988. +\bibitem{blas3} + Jack J.\ Dongarra, Jeremy Du Croz, Sven Hammarling, and Iain Duff, + \doccite{A Set of Level 3 Basic Linear Algebra Subprograms}. + ACM Trans.\ Math.\ Soft., Vol.\ 16, No.\ 1, pp.\ 1--17, Mar.\ 1990. +\bibitem{lapack} + E.\ Anderson, Z.\ Bai, C.\ Bischof, S.\ Blackford, J.\ Demmel, J.\ Dongarra, + J.\ Du Croz, A.\ Greenbaum, S.\ Hammarling, A.\ McKenney, and D.\ Sorensen, + \doccite{LAPACK Users' Guide, Third Edition}. + SIAM, Philadelphia, PA, USA, 1999. +\bibitem{blas-std} + L.\ Susan Blackford, James Demmel, Jack Dongarra, Iain Duff, Sven Hammarling, + Greg Henry, Michael Heroux, Linda Kaufman, Andrew Lumbsdaine, Antoine Petitet, + Roldan Pozo, Karin Remington, and R.\ Client Whaley, + \doccite{An Updated Set of Basic Linear Algebra Subprograms (BLAS)}. + ACM Trans.\ Math.\ Soft., Vol.\ 28, Issue 2, 2002. +\bibitem{flynn-taxonomy} + Michael J.\ Flynn, + \doccite{Very High-Speed Computing Systems}. + Proceedings of the IEEE, Vol.\ 54, Issue 12, 1966. +\end{thebibliography} % FIXME: For unknown reasons, hanging paragraphs are not indented within our % glossaries by default. @@ -65,9 +110,9 @@ \chapter{Bibliography} \clearpage \input{xrefdelta} -\renewcommand{\glossaryname}{Cross-references from ISO \CppXXIII{}} +\renewcommand{\glossaryname}{Cross-references from ISO \CppXVII{}} \renewcommand{\preglossaryhook}{All clause and subclause labels from -ISO \CppXXIII{} (ISO/IEC 14882:2023, \doccite{Programming Languages --- \Cpp{}}) +ISO \CppXVII{} (ISO/IEC 14882:2017, \doccite{Programming Languages --- \Cpp{}}) are present in this document, with the exceptions described below.\\} \renewcommand{\leftmark}{\glossaryname} { @@ -120,7 +165,6 @@ \chapter{Bibliography} \clearpage \renewcommand{\preindexhook}{The entries in this index are rough descriptions; exact specifications are at the indicated page in the general text.\\} -\renewcommand{\leftmark}{Index of impl.-def. behavior} { \raggedright \printindex[impldefindex] diff --git a/source/basic.tex b/source/basic.tex index 7b29e927dd..733d6699d0 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -4,6 +4,11 @@ \gramSec[gram.basic]{Basics} \rSec1[basic.pre]{Preamble} +\indextext{type}% +\indextext{object}% +\indextext{storage class}% +\indextext{scope}% +\indextext{linkage}% \pnum \begin{note} @@ -27,22 +32,22 @@ \end{note} \pnum -\indextext{type}% -\indextext{object}% -\indextext{storage class}% -\indextext{scope}% -\indextext{linkage}% -An \defn{entity} is a value, object, reference, -structured binding, -function, enumerator, type, -class member, bit-field, template, template specialization, namespace, or -pack. +A \defn{name} is an \grammarterm{identifier}\iref{lex.name}, +\grammarterm{conversion-function-id}\iref{class.conv.fct}, +\grammarterm{operator-function-id}\iref{over.oper}, or +\grammarterm{literal-operator-id}\iref{over.literal}. \pnum -A \defn{name} is an \grammarterm{identifier}\iref{lex.name}, -\grammarterm{operator-function-id}\iref{over.oper}, -\grammarterm{literal-operator-id}\iref{over.literal}, or -\grammarterm{conversion-function-id}\iref{class.conv.fct}. +Two names are \defnx{the same}{name!same} if +\begin{itemize} +\item they are \grammarterm{identifier}{s} composed of the same character sequence, or +\item they are \grammarterm{conversion-function-id}{s} formed with +equivalent\iref{temp.over.link} types, or +\item they are \grammarterm{operator-function-id}{s} formed with +the same operator, or +\item they are \grammarterm{literal-operator-id}{s} formed with +the same literal suffix identifier. +\end{itemize} \pnum Every name is introduced by a \defn{declaration}, which is a @@ -57,6 +62,10 @@ \grammarterm{identifier} in a structured binding declaration\iref{dcl.struct.bind}, \item +\grammarterm{identifier} +in a \grammarterm{result-name-introducer} +in a postcondition assertion\iref{dcl.contract.res}, +\item \grammarterm{init-capture}\iref{expr.prim.lambda.capture}, \item \grammarterm{condition} with a \grammarterm{declarator}\iref{stmt.pre}, @@ -65,10 +74,16 @@ \item \grammarterm{using-declarator}\iref{namespace.udecl}, \item -\grammarterm{parameter-declaration}\iref{dcl.fct}, +\grammarterm{parameter-declaration}\iref{dcl.fct,temp.param}, \item \grammarterm{type-parameter}\iref{temp.param}, \item +\grammarterm{type-tt-parameter}\iref{temp.param}, +\item +\grammarterm{variable-tt-parameter}\iref{temp.param}, +\item +\grammarterm{concept-tt-parameter}\iref{temp.param}, +\item \grammarterm{elaborated-type-specifier} that introduces a name\iref{dcl.type.elab}, \item @@ -85,9 +100,15 @@ The interpretation of a \grammarterm{for-range-declaration} produces one or more of the above\iref{stmt.ranged}. \end{note} -An entity $E$ is denoted by the name (if any) -that is introduced by a declaration of $E$ or -by a \grammarterm{typedef-name} introduced by a declaration specifying $E$. + +\pnum +\begin{note} +Some names denote types or templates. +In general, whenever a name is encountered +it is necessary to look it up\iref{basic.lookup} +to determine whether that name denotes one of these entities +before continuing to parse the program that contains it. +\end{note} \pnum A \defn{variable} is introduced by the @@ -95,32 +116,24 @@ a reference other than a non-static data member or of an object. The variable's name, if any, denotes the reference or object. +\pnum +An \defn{entity} is a value, object, reference, +structured binding, +result binding, +function, enumerator, type, +class member, bit-field, template, template specialization, namespace, or +pack. An entity $E$ is denoted by the name (if any) +that is introduced by a declaration of $E$ or +by a \grammarterm{typedef-name} introduced by a declaration specifying $E$. + \pnum A \defnadj{local}{entity} is a variable with automatic storage duration\iref{basic.stc.auto}, a structured binding\iref{dcl.struct.bind} whose corresponding variable is such an entity, +a result binding\iref{dcl.contract.res}, or the \tcode{*\keyword{this}} object\iref{expr.prim.this}. -\pnum -Some names denote types or templates. In general, -whenever a name is encountered it is necessary to determine whether that name denotes -one of these entities before continuing to parse the program that contains it. The -process that determines this is called -\defnx{name lookup}{lookup!name}\iref{basic.lookup}. - -\pnum -Two names are \defnx{the same}{name!same} if -\begin{itemize} -\item they are \grammarterm{identifier}{s} composed of the same character sequence, or -\item they are \grammarterm{operator-function-id}{s} formed with -the same operator, or -\item they are \grammarterm{conversion-function-id}{s} formed -with equivalent\iref{temp.over.link} types, or -\item they are \grammarterm{literal-operator-id}{s}\iref{over.literal} formed with -the same literal suffix identifier. -\end{itemize} - \pnum \indextext{translation unit!name and}% \indextext{linkage}% @@ -135,14 +148,15 @@ \indextext{declaration!definition versus}% \indextext{declaration}% \indextext{declaration!name}% -A declaration\iref{dcl.dcl} may (re)introduce +A declaration\iref{dcl} may (re)introduce one or more names and/or entities into a translation unit. If so, the declaration specifies the interpretation and semantic properties of these names. A declaration of an entity or \grammarterm{typedef-name} $X$ is a redeclaration of $X$ -if another declaration of $X$ is reachable from it\iref{module.reach}. +if another declaration of $X$ is reachable from it\iref{module.reach}; +otherwise, it is a \defnadj{first}{declaration}. A declaration may also have effects including: \begin{itemize} \item a static assertion\iref{dcl.pre}, @@ -228,7 +242,7 @@ a \grammarterm{template-declaration}\iref{temp.pre} whose \grammarterm{template-head} is not followed by either a \grammarterm{concept-definition} or a \grammarterm{declaration} -that defines a function, a class, a variable, or a static data member. +that defines a function, a class, a variable, or a static data member, \item it is an explicit instantiation declaration\iref{temp.explicit}, or \item it is @@ -299,10 +313,10 @@ C() : s() { } C(const C& x): s(x.s) { } C(C&& x): s(static_cast(x.s)) { } - @\rlap{\normalfont\itshape //}@ : s(std::move(x.s)) { } + @\rlap{\textnormal{\textit{//}}}@ : s(std::move(x.s)) { } C& operator=(const C& x) { s = x.s; return *this; } C& operator=(C&& x) { s = static_cast(x.s); return *this; } - @\rlap{\normalfont\itshape //}@ { s = std::move(x.s); return *this; } + @\rlap{\textnormal{\textit{//}}}@ { s = std::move(x.s); return *this; } ~C() { } }; \end{codeblock} @@ -441,32 +455,67 @@ A variable is named by an expression if the expression is an \grammarterm{id-expression} that denotes it. A variable \tcode{x} that is named by a -potentially-evaluated expression $E$ -is \defnx{odr-used}{odr-use} by $E$ unless +potentially-evaluated expression $N$ +that appears at a point $P$ +is \defnx{odr-used}{odr-use} by $N$ unless +\begin{itemize} +\item +\tcode{x} is a reference +that is usable in constant expressions at $P$\iref{expr.const} or +\item +$N$ is an element of the set of potential results of an expression $E$, where \begin{itemize} \item - \tcode{x} is a reference that is - usable in constant expressions\iref{expr.const}, or +$E$ is a discarded-value expression\iref{expr.context} +to which the lvalue-to-rvalue conversion is not applied or \item - \tcode{x} is a variable of non-reference type that is - usable in constant expressions and has no mutable subobjects, and - $E$ is an element of the set of potential results of an expression - of non-volatile-qualified non-class type - to which the lvalue-to-rvalue conversion\iref{conv.lval} is applied, or +\tcode{x} is a non-volatile object +that is usable in constant expressions at $P$ and +has no mutable subobjects and +\begin{itemize} +\item +$E$ is a class member access expression\iref{expr.ref} +naming a non-static data member of reference type and +whose object expression has non-volatile-qualified type or \item - \tcode{x} is a variable of non-reference type, and - $E$ is an element of the set of potential results - of a discarded-value expression\iref{expr.context} - to which the lvalue-to-rvalue conversion is not applied. +the lvalue-to-rvalue conversion\iref{conv.lval} is applied to $E$ and +$E$ has non-volatile-qualified non-class type +\end{itemize} +\end{itemize} \end{itemize} +\begin{example} +\begin{codeblock} +int f(int); +int g(int&); +struct A { + int x; +}; +struct B { + int& r; +}; +int h(bool cond) { + constexpr A a = {1}; + constexpr const volatile A& r = a; // odr-uses \tcode{a} + int _ = f(cond ? a.x : r.x); // does not odr-use \tcode{a} or \tcode{r} + int x, y; + constexpr B b1 = {x}, b2 = {y}; // odr-uses \tcode{x} and \tcode{y} + int _ = g(cond ? b1.r : b2.r); // does not odr-use \tcode{b1} or \tcode{b2} + int _ = ((cond ? x : y), 0); // does not odr-use \tcode{x} or \tcode{y} + return [] { + return b1.r; // error: \tcode{b1} is odr-used here because the object + // referred to by \tcode{b1.r} is not constexpr-referenceable here + }(); +} +\end{codeblock} +\end{example} \pnum A structured binding is odr-used if it appears as a potentially-evaluated expression. \pnum \tcode{*\keyword{this}} is odr-used if \keyword{this} appears as a potentially-evaluated expression -(including as the result of the implicit transformation in the body of a non-static -member function\iref{class.mfct.non.static}). +(including as the result of any implicit transformation to +a class member access expression\iref{expr.prim.id.general}). \pnum A virtual member @@ -497,7 +546,7 @@ \pnum A local entity\iref{basic.pre} -is \defn{odr-usable} in a scope\iref{basic.scope.scope} if: +is \defn{odr-usable} in a scope\iref{basic.scope.scope} if \begin{itemize} \item either the local entity is not \tcode{*\keyword{this}}, or an enclosing class or non-lambda function parameter scope exists and, @@ -508,10 +557,14 @@ between the point at which the entity is introduced and the scope (where \tcode{*\keyword{this}} is considered to be introduced within the innermost enclosing class or non-lambda function definition scope), -either: +either \begin{itemize} -\item the intervening scope is a block scope, or -\item the intervening scope is the function parameter scope of a \grammarterm{lambda-expression} +\item the intervening scope is a block scope, +\item the intervening scope is a contract-assertion scope\iref{basic.scope.contract}, +\item the intervening scope is the function parameter scope of +a \grammarterm{lambda-expression} or \grammarterm{requires-expression}, or +\item the intervening scope is the lambda scope of +a \grammarterm{lambda-expression} that has a \grammarterm{simple-capture} naming the entity or has a \grammarterm{capture-default}, and the block scope of the \grammarterm{lambda-expression} @@ -537,6 +590,27 @@ \end{codeblock} \end{example} +\pnum +\begin{example} +\begin{codeblock} +void g() { + constexpr int x = 1; + auto lambda = [] {}; // OK + lambda.operator()(); // OK, does not consider \tcode{x} at all + lambda.operator()(); // OK, does not odr-use \tcode{x} + lambda.operator()(); // error: odr-uses \tcode{x} from a context where \tcode{x} is not odr-usable +} + +void h() { + constexpr int x = 1; + auto lambda = [] { (T)x; }; // OK + lambda.operator()(); // OK, does not odr-use \tcode{x} + lambda.operator()(); // OK, does not odr-use \tcode{x} + lambda.operator()(); // error: odr-uses \tcode{x} from a context where \tcode{x} is not odr-usable +} +\end{codeblock} +\end{example} + \pnum Every program shall contain at least one definition of every function or variable that is odr-used in that program @@ -586,7 +660,7 @@ \begin{note} The rules for declarations and expressions describe in which contexts complete class types are required. A class -type \tcode{T} must be complete if: +type \tcode{T} must be complete if \begin{itemize} \item an object of type \tcode{T} is defined\iref{basic.def}, or \item a non-static class data member of type \tcode{T} is @@ -613,7 +687,7 @@ is defined\iref{basic.def} or called\iref{expr.call}, or \item a class with a base class of type \tcode{T} is defined\iref{class.derived}, or -\item an lvalue of type \tcode{T} is assigned to\iref{expr.ass}, or +\item an lvalue of type \tcode{T} is assigned to\iref{expr.assign}, or \item the type \tcode{T} is the subject of an \keyword{alignof} expression\iref{expr.alignof}, or \item an \grammarterm{exception-declaration} has type \tcode{T}, reference to @@ -650,7 +724,7 @@ \item In each such definition, corresponding names, looked up 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 +template specializations\iref{temp.spec.partial.match}, except that a name can refer to \begin{itemize} \item a non-volatile const object with internal or no linkage if the object @@ -823,9 +897,11 @@ every other scope $S$ is introduced by a declaration, \grammarterm{parameter-declaration-clause}, -\grammarterm{statement}, or \grammarterm{handler} +\grammarterm{statement}, +\grammarterm{handler}, or +contract assertion (as described in the following subclauses of \ref{basic.scope}) -appearing in another scope which thereby contains $S$. +appearing in another scope, which thereby contains $S$. An \defnadj{enclosing}{scope} at a program point is any scope that contains it; the smallest such scope is said to be the \defnadj{immediate}{scope} at that point. @@ -866,15 +942,14 @@ inhabits the same scope as the \grammarterm{template-declaration}. \item Friend declarations and -declarations of qualified names and -template specializations do not bind names\iref{dcl.meaning}; +declarations of template specializations do not bind names\iref{dcl.meaning}; those with qualified names target a specified scope, and other friend declarations and certain \grammarterm{elaborated-type-specifier}s\iref{dcl.type.elab} target a larger enclosing scope. \item -Block-scope extern declarations target a larger enclosing scope -but bind a name in their immediate scope. +Block-scope extern or function declarations target a larger enclosing scope +but bind a name in their immediate scope\iref{dcl.meaning.general}. \item The names of unscoped enumerators are bound in the two innermost enclosing scopes\iref{dcl.enum}. @@ -888,20 +963,20 @@ \pnum Two non-static member functions have -\defnadjx{corresponding}{object parameters}{object parameter} if: +\defnadjx{corresponding}{object parameters}{object parameter} if \begin{itemize} \item exactly one is an implicit object member function with no \grammarterm{ref-qualifier} and the types of their object parameters\iref{dcl.fct}, -after removing top-level references, +after removing references, are the same, or \item their object parameters have the same type. \end{itemize} \indextext{template!function!corresponding object parameter}% Two non-static member function templates have -\defnadjx{corresponding}{object parameters}{object parameter} if: +\defnadjx{corresponding}{object parameters}{object parameter} if \begin{itemize} \item exactly one is an implicit object member function @@ -942,7 +1017,7 @@ and they do not declare corresponding overloads. \end{itemize} Two function or function template declarations declare -\defn{corresponding overloads} if: +\defn{corresponding overloads} if \begin{itemize} \item both declare functions with the same non-object-parameter-type-list, @@ -1000,10 +1075,24 @@ \pnum A declaration is \defnx{name-independent}{declaration!name-independent} if its name is \tcode{_} (\unicode{005f}{low line}) and it declares +\begin{itemize} +\item a variable with automatic storage duration, -a structured binding not inhabiting a namespace scope, +\item +a structured binding +%FIXME: "and" is strange below; maybe reword to something like: +%FIXME: "that has no \grammarterm{storage-class-specifier} and +%FIXME: that is not inhabiting a namespace scope," +with no \grammarterm{storage-class-specifier} and +not inhabiting a namespace scope, +\item +a result binding\iref{dcl.contract.res}, +\item the variable introduced by an \grammarterm{init-capture}, or -a non-static data member. +\item +%FIXME: "of" is strange below; remove it? +a non-static data member of other than an anonymous union. +\end{itemize} \recommended Implementations should not emit a warning @@ -1117,8 +1206,8 @@ the locus of the declaration that hides it. \begin{example} \begin{codeblock} -const int i = 2; -{ int i[i]; } +const int i = 2; +{ int i[i]; } \end{codeblock} declares a block-scope array of two integers. \end{example} @@ -1204,9 +1293,13 @@ \end{codeblock} \end{example} +\pnum +The locus of a \grammarterm{result-name-introducer}\iref{dcl.contract.res} +is immediately after it. + \pnum The locus of a \grammarterm{concept-definition} -is immediately after its concept-name\iref{temp.concept}. +is immediately after its \grammarterm{concept-name}\iref{temp.concept}. \begin{note} The \grammarterm{constraint-expression} cannot use the \grammarterm{concept-name}. @@ -1278,7 +1371,7 @@ \pnum If a declaration that is not a name-independent declaration and -whose target scope is the block scope $S$ of a +that binds a name in the block scope $S$ of a \begin{itemize} \item \grammarterm{compound-statement} of a \grammarterm{lambda-expression}, @@ -1339,7 +1432,7 @@ in the \grammarterm{lambda-expression}. \item If $P$ is associated with a \grammarterm{requirement-parameter-list}, -its scope extends to the end of the \grammarterm{requirement-body} of the requires-expression. +its scope extends to the end of the \grammarterm{requirement-body} of the \grammarterm{requires-expression}. \item If $P$ is associated with a \grammarterm{deduction-guide}, its scope extends to the end of the \grammarterm{deduction-guide}. @@ -1419,7 +1512,11 @@ \rSec2[basic.scope.temp]{Template parameter scope}% \pnum -Each template \grammarterm{template-parameter} introduces +Each +\grammarterm{type-tt-parameter}, +\grammarterm{variable-tt-parameter}, and +\grammarterm{concept-tt-parameter} +introduces a \defnadj{template parameter}{scope} that includes the \grammarterm{template-head} of the \grammarterm{template-parameter}. @@ -1439,6 +1536,30 @@ a template parameter scope as a parent scope. \end{note} +\rSec2[basic.scope.contract]{Contract-assertion scope}% + +\pnum +Each contract assertion\iref{basic.contract} +$C$ introduces a \defnadj{contract-assertion}{scope} +that includes $C$. + +\pnum +If a \grammarterm{result-name-introducer}\iref{dcl.contract.res} +that is not name-independent\iref{basic.scope.scope} +and whose enclosing postcondition assertion +is associated with a function \tcode{F} +potentially conflicts with +a declaration whose target scope is +\begin{itemize} +\item +the function parameter scope of \tcode{F} or +\item +if associated with a \grammarterm{lambda-declarator}, +the nearest enclosing lambda scope +of the precondition assertion\iref{expr.prim.lambda}, +\end{itemize} +the program is ill-formed. + \indextext{scope|)} \rSec1[basic.lookup]{Name lookup}% @@ -1449,13 +1570,13 @@ \indextext{scope!name lookup and|see{lookup, name}}% \pnum +\defnx{Name lookup}{lookup!name} associates the use of a name +with a set of declarations\iref{basic.def} of that name. The name lookup rules apply uniformly to all names (including \grammarterm{typedef-name}{s}\iref{dcl.typedef}, \grammarterm{namespace-name}{s}\iref{basic.namespace}, and \grammarterm{class-name}{s}\iref{class.name}) wherever the grammar allows -such names in the context discussed by a particular rule. Name lookup -associates the use of a name with a set of declarations\iref{basic.def} of -that name. +such names in the context discussed by a particular rule. Unless otherwise specified, the program is ill-formed if no declarations are found. If the declarations found by name lookup @@ -1940,7 +2061,7 @@ then lookup for the name also includes the result of \defnadj{argument-dependent}{lookup} in a set of associated namespaces that depends on the types of the arguments -(and for template template arguments, the namespace of the template argument), +(and for type template template arguments, the namespace of the template argument), as specified below. \begin{example} \begin{codeblock} @@ -2008,7 +2129,7 @@ to be considered. The set of entities is determined entirely by the types of the function arguments -(and any template template arguments). +(and any type template template arguments). Any \grammarterm{typedef-name}s and \grammarterm{using-declaration}{s} used to specify the types do not contribute to this set. @@ -2022,17 +2143,20 @@ its associated entities are: the class itself; the class of which it is a member, if any; -and its direct and indirect base classes. +and, if it is a complete type, its direct and indirect base classes. Furthermore, if \tcode{T} is a class template specialization, its associated entities also include: the entities associated with the types of the template arguments provided for template type parameters; -the templates used as template template arguments; and -the classes of which any member templates used as template template +the templates used as type template template arguments; and +the classes of which any member templates used as type template template arguments are members. \begin{note} -Non-type template arguments do not +Constant template arguments, +variable template template arguments, and +concept template arguments +do not contribute to the set of associated entities. \end{note} @@ -2063,8 +2187,8 @@ parameter types and return type. Additionally, if the aforementioned overload set is named with a \grammarterm{template-id}, its associated entities also include -its template \grammarterm{template-argument}{s} and -those associated with its type \grammarterm{template-argument}s. +its template template arguments and +those associated with its type template arguments. \pnum The \term{associated namespaces} for a call are @@ -2170,7 +2294,7 @@ followed by a \tcode{::} scope resolution operator considers only namespaces, types, and templates whose specializations are types. -If a name, \grammarterm{template-id}, or \grammarterm{decltype-specifier} +If a name, \grammarterm{template-id}, or \grammarterm{computed-type-specifier} is followed by a \tcode{::}, it shall designate a namespace, class, enumeration, or dependent type, and the \tcode{::} is never interpreted as @@ -2619,6 +2743,7 @@ \pnum \indextext{program}% +\indextext{linking}% A \defn{program} consists of one or more translation units\iref{lex.separate} linked together. A translation unit consists of a sequence of declarations. @@ -2631,28 +2756,18 @@ \pnum \indextext{translation unit}% -A name is said to have \defn{linkage} when it can denote the same -object, reference, function, type, template, namespace or value as a -name introduced by a declaration in another scope: -\begin{itemize} -\item When a name has \defnadj{external}{linkage}, -the entity it denotes -can be referred to by names from scopes of other translation units or -from other scopes of the same translation unit. - -\item When a name has \defnx{module linkage}{linkage!module}, -the entity it denotes -can be referred to by names from other scopes of the same module unit\iref{module.unit} or -from scopes of other module units of that same module. - -\item When a name has \defnadj{internal}{linkage}, -the entity it denotes -can be referred to by names from other scopes in the same translation -unit. - -\item When a name has \indextext{linkage!no}\defn{no linkage}, the entity it denotes -cannot be referred to by names from other scopes. -\end{itemize} +A name can have +\defnadj{external}{linkage}, +\defnadj{module}{linkage}, +\defnadj{internal}{linkage}, or +\defnadj{no}{linkage}, +as determined by the rules below. +\begin{note} +All declarations of an entity with a name with internal linkage +appear in the same translation unit. +All declarations of an entity with module linkage +are attached to the same module. +\end{note} \pnum \indextext{linkage!\idxcode{static} and}% @@ -2690,8 +2805,8 @@ \pnum An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage. -The name of an entity that belongs to a namespace scope -that has not been given internal linkage above +The name of an entity that belongs to a namespace scope, +that has not been given internal linkage above, and that is the name of \begin{itemize} \item a variable; or @@ -2713,6 +2828,24 @@ has its linkage determined as follows: \begin{itemize} \item +\indextext{friend function!linkage of}% +if the entity is a function or function template +first declared in a friend declaration and +that declaration is a definition and +the enclosing class is defined within an \grammarterm{export-declaration}, +the name has the same linkage, if any, +as the name of the enclosing class\iref{class.friend}; +\item +otherwise, +\indextext{friend function!linkage of}% +if the entity is a function or function template +declared in a friend declaration and +a corresponding non-friend declaration is reachable, +%FIXME: Which declaration is "that prior declaration"? +%FIXME: "prior" with respect to what? And what about dependent lookup? +the name has the linkage determined from that prior declaration, +\item +otherwise, if the enclosing namespace has internal linkage, the name has internal linkage; \item @@ -3053,11 +3186,6 @@ \indextext{character set!basic literal}% literal character set\iref{lex.charset} and the eight-bit code units of the Unicode -\begin{footnote} -Unicode\textregistered\ is a registered trademark of Unicode, Inc. -This information is given for the convenience of users of this document and -does not constitute an endorsement by ISO or IEC of this product. -\end{footnote} \indextext{UTF-8}% UTF-8 encoding form and is composed of a contiguous sequence of @@ -3066,11 +3194,10 @@ The number of bits in a byte is reported by the macro \tcode{CHAR_BIT} in the header \libheaderref{climits}. \end{footnote} -the number of which is \impldef{bits in a byte}. The least -significant bit is called the \defn{low-order bit}; the most -significant bit is called the \defn{high-order bit}. The memory -available to a \Cpp{} program consists of one or more sequences of -contiguous bytes. Every byte has a unique address. +the number of which is \impldef{bits in a byte}. +The memory available to a \Cpp{} program consists of one or more sequences of +contiguous bytes. +Every byte has a unique address. \pnum \begin{note} @@ -3079,7 +3206,9 @@ \end{note} \pnum -A \defn{memory location} is either an object of scalar type that is not a bit-field +A \defn{memory location} is +the storage occupied by the object representation of +either an object of scalar type that is not a bit-field or a maximal sequence of adjacent bit-fields all having nonzero width. \begin{note} Various @@ -3173,7 +3302,7 @@ in storage associated with a member subobject or array element \placeholder{e} (which may or may not be within its lifetime), the created object -is a subobject of \placeholder{e}'s containing object if: +is a subobject of \placeholder{e}'s containing object if \begin{itemize} \item the lifetime of \placeholder{e}'s containing object has begun and not ended, and @@ -3190,7 +3319,7 @@ of type ``array of $N$ \tcode{\keyword{unsigned} \keyword{char}}'' or of type ``array of $N$ \tcode{std::byte}''\iref{cstddef.syn}, that array \defn{provides storage} -for the created object if: +for the created object if \begin{itemize} \item the lifetime of \placeholder{e} has begun and not ended, and @@ -3233,7 +3362,7 @@ \pnum \indextext{object!nested within}% -An object \placeholder{a} is \defn{nested within} another object \placeholder{b} if: +An object \placeholder{a} is \defn{nested within} another object \placeholder{b} if \begin{itemize} \item \placeholder{a} is a subobject of \placeholder{b}, or @@ -3300,6 +3429,12 @@ standard-layout type\iref{basic.types.general} shall occupy contiguous bytes of storage. +\pnum +An object is a \defnadj{potentially non-unique}{object} if it is +a string literal object\iref{lex.string}, +the backing array of an initializer list\iref{dcl.init.ref}, or +a subobject thereof. + \pnum \indextext{most derived object!bit-field}% \indextext{most derived object!zero size subobject}% @@ -3308,11 +3443,13 @@ Two objects with overlapping lifetimes that are not bit-fields -may have the same address -if one is nested within the other, +may have the same address if +\begin{itemize} +\item one is nested within the other, +\item at least one is a subobject of zero size and they are not of similar types\iref{conv.qual}, or -if at least one is a subobject of zero size -and they are of different types; +\item they are both potentially non-unique objects; +\end{itemize} otherwise, they have distinct addresses and occupy disjoint bytes of storage. \begin{footnote} @@ -3326,6 +3463,14 @@ static const char test1 = 'x'; static const char test2 = 'x'; const bool b = &test1 != &test2; // always \tcode{true} + +static const char (&r) [] = "x"; +static const char *s = "x"; +static std::initializer_list il = { 'x' }; +const bool b2 = r != il.begin(); // unspecified result +const bool b3 = r != s; // unspecified result +const bool b4 = il.begin() != &test1; // always \tcode{true} +const bool b5 = r != &test1; // always \tcode{true} \end{codeblock} \end{example} The address of a non-bit-field subobject of zero size is @@ -3383,13 +3528,15 @@ \end{example} \pnum -An operation that begins the lifetime of +Except during constant evaluation, +an operation that begins the lifetime of an array of \tcode{unsigned char} or \tcode{std::byte} implicitly creates objects within the region of storage occupied by the array. \begin{note} The array object provides storage for these objects. \end{note} -Any implicit or explicit invocation of a function +Except during constant evaluation, +any implicit or explicit invocation of a function named \tcode{\keyword{operator} \keyword{new}} or \tcode{\keyword{operator} \keyword{new}[]} implicitly creates objects in the returned region of storage and returns a pointer to a suitable created object. @@ -3399,16 +3546,115 @@ \end{note} \indextext{object model|)} +\rSec2[basic.align]{Alignment} + +\pnum +Object types have \defnx{alignment requirements}{alignment requirement!implementation-defined}\iref{basic.fundamental,basic.compound} +which place restrictions on the addresses at which an object of that type +may be allocated. An \defn{alignment} is an \impldef{alignment} +integer value representing the number of bytes between successive addresses +at which a given object can be allocated. An object type imposes an alignment +requirement on every object of that type; stricter alignment can be requested +using the alignment specifier\iref{dcl.align}. +Attempting to create an object\iref{intro.object} in storage that +does not meet the alignment requirements of the object's type +is undefined behavior. + +\pnum +A \defnadj{fundamental}{alignment} is represented by an alignment +less than or equal to the greatest alignment supported by the implementation in +all contexts, which is equal to +\tcode{\keyword{alignof}(std::max_align_t)}\iref{support.types}. +The alignment required for a type may be different when it is used as the type +of a complete object and when it is used as the type of a subobject. +\begin{example} +\begin{codeblock} +struct B { long double d; }; +struct D : virtual B { char c; }; +\end{codeblock} + +When \tcode{D} is the type of a complete object, it will have a subobject of +type \tcode{B}, so it must be aligned appropriately for a \tcode{\keyword{long} \keyword{double}}. +If \tcode{D} appears as a subobject of another object that also has \tcode{B} +as a virtual base class, the \tcode{B} subobject might be part of a different +subobject, reducing the alignment requirements on the \tcode{D} subobject. +\end{example} +The result of the \keyword{alignof} operator reflects the alignment +requirement of the type in the complete-object case. + +\pnum +An \defnadj{extended}{alignment} is represented by an alignment +greater than \tcode{\keyword{alignof}(std::max_align_t)}. It is \impldef{support for extended alignments} +whether any extended alignments are supported and the contexts in which they are +supported\iref{dcl.align}. A type having an extended alignment +requirement is an \defnadj{over-aligned}{type}. +\begin{note} +Every over-aligned type is or contains a class type +to which extended alignment applies (possibly through a non-static data member). +\end{note} +A \defnadj{new-extended}{alignment} is represented by +an alignment greater than \mname{STDCPP_DEFAULT_NEW_ALIGNMENT}\iref{cpp.predefined}. + +\pnum +Alignments are represented as values of the type \tcode{std::size_t}. +Valid alignments include only those values returned by an \keyword{alignof} +expression for the fundamental types plus an additional \impldef{alignment additional +values} +set of values, which may be empty. +Every alignment value shall be a non-negative integral power of two. + +\pnum +Alignments have an order from \defnx{weaker}{alignment!weaker} to +\defnx{stronger}{alignment!stronger} or \defnx{stricter}{alignment!stricter} alignments. Stricter +alignments have larger alignment values. An address that satisfies an alignment +requirement also satisfies any weaker valid alignment requirement. + +\pnum +The alignment requirement of a complete type can be queried using an +\keyword{alignof} expression\iref{expr.alignof}. Furthermore, +the narrow character types\iref{basic.fundamental} shall have the weakest +alignment requirement. +\begin{note} +This enables the ordinary character types to be used as the +underlying type for an aligned memory area\iref{dcl.align}. +\end{note} + +\pnum +Comparing alignments is meaningful and provides the obvious results: + +\begin{itemize} +\item Two alignments are equal when their numeric values are equal. +\item Two alignments are different when their numeric values are not equal. +\item When an alignment is larger than another it represents a stricter alignment. +\end{itemize} + +\pnum +\begin{note} +The runtime pointer alignment function\iref{ptr.align} +can be used to obtain an aligned pointer within a buffer; +an \grammarterm{alignment-specifier}\iref{dcl.align} +can be used to align storage explicitly. +\end{note} + +\pnum +If a request for a specific extended alignment in a specific context is not +supported by an implementation, the program is ill-formed. + \rSec2[basic.life]{Lifetime} +\pnum +In this subclause, ``before'' and ``after'' refer to the ``happens before'' +relation\iref{intro.multithread}. + \pnum \indextext{object lifetime|(}% The \defn{lifetime} of an object or reference is a runtime property of the object or reference. A variable is said to have \defnadj{vacuous}{initialization} -if it is default-initialized and, +if it is default-initialized, no other initialization is performed, and, if it is of class type or a (possibly multidimensional) array thereof, -that class type has a trivial default constructor. +a trivial constructor of that class type is selected for +the default-initialization. The lifetime of an object of type \tcode{T} begins when: \begin{itemize} \item storage with the proper alignment and size @@ -3502,7 +3748,7 @@ if the pointer were of type \tcode{\keyword{void}*} is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The -program has undefined behavior if: +program has undefined behavior if \begin{itemize} \item the pointer is used as the operand of a \grammarterm{delete-expression}, @@ -3565,7 +3811,7 @@ a glvalue refers to allocated storage\iref{basic.stc.dynamic.allocation}, and using the properties of the glvalue that do not depend on its value is -well-defined. The program has undefined behavior if: +well-defined. The program has undefined behavior if \begin{itemize} \item the glvalue is used to access the object, or \item the glvalue is used to call a non-static member function of the object, or @@ -3575,18 +3821,14 @@ \keyword{typeid}. \end{itemize} +\begin{note} +Therefore, undefined behavior results +if an object that is being constructed in one thread is referenced from another +thread without adequate synchronization. +\end{note} + \pnum -If, after the lifetime of an object has ended and before the storage -which the object occupied is reused or released, a new object is created -at the storage location which the original object occupied, a pointer -that pointed to the original object, a reference that referred to the -original object, or the name of the original object will automatically -refer to the new object and, once the lifetime of the new object has -started, can be used to manipulate the new object, if -the original object is transparently replaceable (see below) -by the new object. -An object $o_1$ is \defn{transparently replaceable} -by an object $o_2$ if: +An object $o_1$ is \defn{transparently replaceable} by an object $o_2$ if \begin{itemize} \item the storage that $o_2$ occupies exactly overlays the storage that $o_1$ occupied, and @@ -3603,6 +3845,17 @@ $o_1$ and $o_2$ are direct subobjects of objects $p_1$ and $p_2$, respectively, and $p_1$ is transparently replaceable by $p_2$. \end{itemize} + +\pnum +After the lifetime of an object has ended and before the storage which the +object occupied is reused or released, if a new object is created at the +storage location which the original object occupied and the original object was +transparently replaceable by the new object, a pointer that pointed to the +original object, a reference that referred to the original object, or the name +of the original object will automatically refer to the new object and, once the +lifetime of the new object has started, can be used to manipulate the new +object. + \begin{example} \begin{codeblock} struct C { @@ -3654,12 +3907,12 @@ \begin{codeblock} class T { }; struct B { - ~B(); + ~B(); }; void h() { - B b; - new (&b) T; + B b; + new (&b) T; } // undefined behavior at block exit \end{codeblock} \end{example} @@ -3684,37 +3937,49 @@ } \end{codeblock} \end{example} - -\pnum -In this subclause, ``before'' and ``after'' refer to the ``happens before'' -relation\iref{intro.multithread}. -\begin{note} -Therefore, undefined behavior results -if an object that is being constructed in one thread is referenced from another -thread without adequate synchronization. -\end{note} \indextext{object lifetime|)} -\rSec2[basic.indet]{Indeterminate values} +\rSec2[basic.indet]{Indeterminate and erroneous values} \pnum -\indextext{value!indeterminate}% -\indextext{indeterminate value}% When storage for an object with automatic or dynamic storage duration -is obtained, the object has an \defnadj{indeterminate}{value}, and if -no initialization is performed for the object, that object retains an -indeterminate value until that value is replaced\iref{expr.ass}. +is obtained, +the bytes comprising the storage for the object +have the following initial value: +\begin{itemize} +\item +If the object has dynamic storage duration, or +is the object associated with a variable or function parameter +whose first declaration is marked with +the \tcode{[[indeterminate]]} attribute\iref{dcl.attr.indet}, +the bytes have \defnadjx{indeterminate}{values}{value}; +\item +otherwise, the bytes have \defnadjx{erroneous}{values}{value}, +where each value is determined by the implementation +independently of the state of the program. +\end{itemize} +If no initialization is performed for an object (including subobjects), +such a byte retains its initial value +until that value is replaced\iref{dcl.init.general,expr.assign}. +If any bit in the value representation has an indeterminate value, +the object has an indeterminate value; +otherwise, if any bit in the value representation has an erroneous value, +the object has an erroneous value\iref{conv.lval}. \begin{note} Objects with static or thread storage duration are zero-initialized, see~\ref{basic.start.static}. \end{note} \pnum -If an indeterminate value is produced by an evaluation, -the behavior is undefined except in the following cases: +Except in the following cases, +if an indeterminate value is produced by an evaluation, +the behavior is undefined, and +if an erroneous value is produced by an evaluation, +the behavior is erroneous and +the result of the evaluation is the value so produced but is not erroneous: \begin{itemize} \item - If an indeterminate value of + If an indeterminate or erroneous value of unsigned ordinary character type\iref{basic.fundamental} or \tcode{std::byte} type\iref{cstddef.syn} is produced by the evaluation of: @@ -3731,37 +3996,69 @@ \item a discarded-value expression\iref{expr.context}, \end{itemize} - then the result of the operation is an indeterminate value. + then the result of the operation is an indeterminate value or + that erroneous value, respectively. \item - If an indeterminate value of + If an indeterminate or erroneous value of unsigned ordinary character type or \tcode{std::byte} type is produced by the evaluation of - the right operand of a simple assignment operator\iref{expr.ass} + the right operand of a simple assignment operator\iref{expr.assign} whose first operand is an lvalue of unsigned ordinary character type or \tcode{std::byte} type, - an indeterminate value replaces + an indeterminate value or that erroneous value, respectively, replaces the value of the object referred to by the left operand. \item - If an indeterminate value of unsigned ordinary character type + If an indeterminate or erroneous value of unsigned ordinary character type is produced by the evaluation of the initialization expression when initializing an object of unsigned ordinary character type, that object is initialized to an indeterminate - value. + value or that erroneous value, respectively. \item If an indeterminate value of unsigned ordinary character type or \tcode{std::byte} type is produced by the evaluation of the initialization expression when initializing an object of \tcode{std::byte} type, - that object is initialized to an indeterminate value. + that object is initialized to an indeterminate value or + that erroneous value, respectively. \end{itemize} +Converting an indeterminate or erroneous value of +unsigned ordinary character type or \tcode{std::byte} type +produces an indeterminate or erroneous value, respectively. +In the latter case, +the result of the conversion is the value of the converted operand. \begin{example} \begin{codeblock} int f(bool b) { - unsigned char c; - unsigned char d = c; // OK, \tcode{d} has an indeterminate value + unsigned char *c = new unsigned char; + unsigned char d = *c; // OK, \tcode{d} has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if \tcode{b} is \tcode{true} } + +int g(bool b) { + unsigned char c; + unsigned char d = c; // no erroneous behavior, but \tcode{d} has an erroneous value + + assert(c == d); // holds, both integral promotions have erroneous behavior + + int e = d; // erroneous behavior + return b ? d : 0; // erroneous behavior if \tcode{b} is \tcode{true} +} + +void h() { + int d1, d2; + + int e1 = d1; // erroneous behavior + int e2 = d1; // erroneous behavior + + assert(e1 == e2); // holds + assert(e1 == d1); // holds, erroneous behavior + assert(e2 == d1); // holds, erroneous behavior + + std::memcpy(&d2, &d1, sizeof(int)); // no erroneous behavior, but \tcode{d2} has an erroneous value + assert(e1 == d2); // holds, erroneous behavior + assert(e2 == d2); // holds, erroneous behavior +} \end{codeblock} \end{example} @@ -3781,6 +4078,10 @@ \item automatic storage duration \item dynamic storage duration \end{itemize} +\begin{note} +After the duration of a region of storage has ended, +the use of pointers to that region of storage is limited\iref{basic.compound}. +\end{note} \pnum \indextext{storage duration!static}% @@ -3788,30 +4089,21 @@ \indextext{storage duration!automatic}% \indextext{storage duration!dynamic}% Static, thread, and automatic storage durations are associated with objects -introduced by declarations\iref{basic.def} and implicitly created by -the implementation\iref{class.temporary}. The dynamic storage duration +introduced by declarations\iref{basic.def} and +with temporary objects\iref{class.temporary}. +The dynamic storage duration is associated with objects created by a -\grammarterm{new-expression}\iref{expr.new}. +\grammarterm{new-expression}\iref{expr.new} or +with implicitly created objects\iref{intro.object}. \pnum The storage duration categories apply to references as well. \pnum -When the end of the duration of a region of storage is reached, -the values of all pointers -representing the address of any part of that region of storage -become invalid pointer values\iref{basic.compound}. -Indirection through an invalid pointer value and -passing an invalid pointer value to a deallocation function -have undefined behavior. -Any other use of an invalid pointer value has -\impldef{any use of an invalid pointer other than to perform indirection or deallocate} -behavior. -\begin{footnote} -Some implementations might define that -copying an invalid pointer value -causes a system-generated runtime fault. -\end{footnote} +\indextext{storage duration!class member}% +The storage duration of subobjects and reference members +is that of their complete object\iref{intro.object}. +\indextext{storage duration|)}% \rSec3[basic.stc.static]{Static storage duration} @@ -3869,15 +4161,16 @@ \pnum \indextext{storage duration!local object}% -Variables that belong to a block or parameter scope and are +Variables that belong to a block scope and are not explicitly declared \keyword{static}, \keyword{thread_local}, or \keyword{extern} have \defnadj{automatic}{storage duration}. The storage -for these entities lasts until the block in which they are created exits. - -\pnum +for such variables lasts until the block in which they are created exits. \begin{note} These variables are initialized and destroyed as described in~\ref{stmt.dcl}. \end{note} +Variables that belong to a parameter scope also have automatic storage duration. +The storage for a function parameter lasts until +immediately after its destruction\iref{expr.call}. \pnum If a variable with automatic storage duration has initialization or a destructor with side @@ -3913,27 +4206,22 @@ \pnum The library provides default definitions for the global allocation and deallocation functions. Some global allocation and deallocation -functions are replaceable\iref{new.delete}; -these are attached to the global module\iref{module.unit}. -A \Cpp{} program shall -provide at most one definition of a replaceable allocation or -deallocation function. Any such function definition replaces the default -version provided in the library\iref{replacement.functions}. The -following allocation and deallocation functions\iref{support.dynamic} +functions are replaceable\iref{dcl.fct.def.replace}. +The following allocation and deallocation functions\iref{support.dynamic} are implicitly declared in global scope in each translation unit of a program. \begin{codeblock} -[[nodiscard]] void* operator new(std::size_t); -[[nodiscard]] void* operator new(std::size_t, std::align_val_t); +void* operator new(std::size_t); +void* operator new(std::size_t, std::align_val_t); void operator delete(void*) noexcept; void operator delete(void*, std::size_t) noexcept; void operator delete(void*, std::align_val_t) noexcept; void operator delete(void*, std::size_t, std::align_val_t) noexcept; -[[nodiscard]] void* operator new[](std::size_t); -[[nodiscard]] void* operator new[](std::size_t, std::align_val_t); +void* operator new[](std::size_t); +void* operator new[](std::size_t, std::align_val_t); void operator delete[](void*) noexcept; void operator delete[](void*, std::size_t) noexcept; @@ -4070,11 +4358,13 @@ functions in the \Cpp{} standard library. \begin{note} In particular, a -global allocation function is not called to allocate storage for objects -with static storage duration\iref{basic.stc.static}, for objects or references -with thread storage duration\iref{basic.stc.thread}, for objects of -type \tcode{std::type_info}\iref{expr.typeid}, or for an -exception object\iref{except.throw}. +global allocation function is not called to allocate storage +for objects with static storage duration\iref{basic.stc.static}, +for objects or references with thread storage duration\iref{basic.stc.thread}, +for objects of type \tcode{std::type_info}\iref{expr.typeid}, +for an object of type \tcode{std::contracts::contract_violation} +when a contract violation occurs\iref{basic.contract.eval}, or +for an exception object\iref{except.throw}. \end{note} \rSec4[basic.stc.dynamic.deallocation]{Deallocation functions} @@ -4144,108 +4434,6 @@ deallocation function shall deallocate the storage referenced by the pointer, ending the duration of the region of storage. -\rSec3[basic.stc.inherit]{Duration of subobjects} - -\pnum -\indextext{storage duration!class member}% -The storage duration of subobjects and reference members -is that of their complete object\iref{intro.object}. -\indextext{storage duration|)}% - -\rSec2[basic.align]{Alignment} - -\pnum -Object types have \defnx{alignment requirements}{alignment requirement!implementation-defined}\iref{basic.fundamental,basic.compound} -which place restrictions on the addresses at which an object of that type -may be allocated. An \defn{alignment} is an \impldef{alignment} -integer value representing the number of bytes between successive addresses -at which a given object can be allocated. An object type imposes an alignment -requirement on every object of that type; stricter alignment can be requested -using the alignment specifier\iref{dcl.align}. -Attempting to create an object\iref{intro.object} in storage that -does not meet the alignment requirements of the object's type -is undefined behavior. - -\pnum -A \defnadj{fundamental}{alignment} is represented by an alignment -less than or equal to the greatest alignment supported by the implementation in -all contexts, which is equal to -\tcode{\keyword{alignof}(std::max_align_t)}\iref{support.types}. -The alignment required for a type may be different when it is used as the type -of a complete object and when it is used as the type of a subobject. -\begin{example} -\begin{codeblock} -struct B { long double d; }; -struct D : virtual B { char c; }; -\end{codeblock} - -When \tcode{D} is the type of a complete object, it will have a subobject of -type \tcode{B}, so it must be aligned appropriately for a \tcode{\keyword{long} \keyword{double}}. -If \tcode{D} appears as a subobject of another object that also has \tcode{B} -as a virtual base class, the \tcode{B} subobject might be part of a different -subobject, reducing the alignment requirements on the \tcode{D} subobject. -\end{example} -The result of the \keyword{alignof} operator reflects the alignment -requirement of the type in the complete-object case. - -\pnum -An \defnadj{extended}{alignment} is represented by an alignment -greater than \tcode{\keyword{alignof}(std::max_align_t)}. It is \impldef{support for extended alignments} -whether any extended alignments are supported and the contexts in which they are -supported\iref{dcl.align}. A type having an extended alignment -requirement is an \defnadj{over-aligned}{type}. -\begin{note} -Every over-aligned type is or contains a class type -to which extended alignment applies (possibly through a non-static data member). -\end{note} -A \defnadj{new-extended}{alignment} is represented by -an alignment greater than \mname{STDCPP_DEFAULT_NEW_ALIGNMENT}\iref{cpp.predefined}. - -\pnum -Alignments are represented as values of the type \tcode{std::size_t}. -Valid alignments include only those values returned by an \keyword{alignof} -expression for the fundamental types plus an additional \impldef{alignment additional -values} -set of values, which may be empty. -Every alignment value shall be a non-negative integral power of two. - -\pnum -Alignments have an order from \defnx{weaker}{alignment!weaker} to -\defnx{stronger}{alignment!stronger} or \defnx{stricter}{alignment!stricter} alignments. Stricter -alignments have larger alignment values. An address that satisfies an alignment -requirement also satisfies any weaker valid alignment requirement. - -\pnum -The alignment requirement of a complete type can be queried using an -\keyword{alignof} expression\iref{expr.alignof}. Furthermore, -the narrow character types\iref{basic.fundamental} shall have the weakest -alignment requirement. -\begin{note} -This enables the ordinary character types to be used as the -underlying type for an aligned memory area\iref{dcl.align}. -\end{note} - -\pnum -Comparing alignments is meaningful and provides the obvious results: - -\begin{itemize} -\item Two alignments are equal when their numeric values are equal. -\item Two alignments are different when their numeric values are not equal. -\item When an alignment is larger than another it represents a stricter alignment. -\end{itemize} - -\pnum -\begin{note} -The runtime pointer alignment function\iref{ptr.align} -can be used to obtain an aligned pointer within a buffer; -an \grammarterm{alignment-specifier}\iref{dcl.align} -can be used to align storage explicitly. -\end{note} - -\pnum -If a request for a specific extended alignment in a specific context is not -supported by an implementation, the program is ill-formed. - \rSec2[class.temporary]{Temporary objects} \pnum @@ -4257,15 +4445,9 @@ Temporary objects are created \begin{itemize} \item -when a prvalue is converted to an xvalue\iref{conv.rval}, +when a prvalue is converted to an xvalue\iref{conv.rval} and \item -when needed by the implementation to pass or return an object of trivially copyable type (see below), -and -\item -when throwing an exception\iref{except.throw}. -\begin{note} -The lifetime of exception objects is described in~\ref{except.throw}. -\end{note} +when needed by the implementation to pass or return an object of suitable type (see below). \end{itemize} Even when the creation of the temporary object is unevaluated\iref{expr.context}, @@ -4290,7 +4472,9 @@ when binding a reference to a prvalue\iref{dcl.init.ref,expr.type.conv, expr.dynamic.cast,expr.static.cast,expr.const.cast,expr.cast}, \item -when performing member access on a class prvalue\iref{expr.ref,expr.mptr.oper}, +when performing certain member accesses on a class prvalue\iref{expr.ref,expr.mptr.oper}, +\item +when invoking an implicit object member function on a class prvalue\iref{expr.call}, \item when performing an array-to-pointer conversion or subscripting on an array prvalue\iref{conv.array,expr.sub}, \item @@ -4347,34 +4531,49 @@ \pnum When an object of class type \tcode{X} -is passed to or returned from a function, -if \tcode{X} has at least one eligible copy or move constructor\iref{special}, -each such constructor is trivial, +is passed to or returned from a potentially-evaluated function call, +if \tcode{X} is +\begin{itemize} +\item +a scalar type or +\item +a class type that +has at least one eligible copy or move constructor\iref{special}, +where each such constructor is trivial, and the destructor of \tcode{X} is either trivial or deleted, +\end{itemize} implementations are permitted -to create a temporary object -to hold the function parameter or result object. -The temporary object is constructed -from the function argument or return value, respectively, -and the function's parameter or return object -is initialized as if by -using the eligible trivial constructor to copy the temporary -(even if that constructor is inaccessible +to create temporary objects +to hold the function parameter or result object, +as follows: +\begin{itemize} +\item +The first such temporary object +is constructed from the function argument or return value, respectively. +\item +Each successive temporary object +is initialized from the previous one +as if by direct-initialization if \tcode{X} is a scalar type, +otherwise by using an eligible trivial constructor. +\item +The function parameter or return object is initialized +from the final temporary +as if by direct-initialization if \tcode{X} is a scalar type, +otherwise by using an eligible trivial constructor. +\end{itemize} +(In all cases, the eligible constructor is used +even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object). \begin{note} -This latitude is granted to allow objects of class type to be passed to or returned from functions in registers. +This latitude is granted to allow objects +to be passed to or returned from functions in registers. \end{note} \pnum \indextext{temporary!constructor for}% \indextext{temporary!destructor for}% \indextext{temporary!destruction of}% -When an implementation introduces a temporary object of a class that has a -non-trivial constructor\iref{class.default.ctor,class.copy.ctor}, -it shall ensure that a constructor is called for the temporary object. -Similarly, the destructor shall be called for a temporary with a non-trivial -destructor\iref{class.dtor}. Temporary objects are destroyed as the last step in evaluating the full-expression\iref{intro.execution} @@ -4392,7 +4591,7 @@ \pnum \indextext{initializer!temporary and declarator}% \indextext{temporary!order of destruction of}% -There are four contexts in which temporaries are destroyed at a different +There are five contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when a default constructor is called to initialize an element of an array with no corresponding initializer\iref{dcl.init}. @@ -4497,8 +4696,6 @@ persists until the completion of the full-expression containing the \grammarterm{expression-list}. -\item The lifetime of a temporary bound to the returned value in a function \tcode{return} statement\iref{stmt.return} is not extended; the temporary is destroyed at the end of the full-expression in the \tcode{return} statement. - \item A temporary bound to a reference in a \grammarterm{new-initializer}\iref{expr.new} persists until the completion of the full-expression containing the \grammarterm{new-initializer}. \begin{note} This might introduce a dangling reference. @@ -4513,7 +4710,7 @@ \end{itemize} \pnum -The fourth context is when a temporary object other than a function parameter object +The fourth context is when a temporary object is created in the \grammarterm{for-range-initializer} of a range-based \keyword{for} statement. If such a temporary object would otherwise be destroyed at the end of the \grammarterm{for-range-initializer} full-expression, @@ -4521,10 +4718,21 @@ initialized by the \grammarterm{for-range-initializer}. \pnum -The destruction of a temporary whose lifetime is not extended -beyond the full-expression in which it was created -is sequenced before the destruction of every -temporary which is constructed earlier in the same full-expression. +The fifth context is when a temporary object +is created in a structured binding declaration\iref{dcl.struct.bind}. +Any temporary objects introduced by +the \grammarterm{initializer}{s} for the variables +with unique names +are destroyed at the end of the structured binding declaration. + +\pnum +Let \tcode{x} and \tcode{y} each be either +a temporary object whose lifetime is not extended, or +a function parameter. +If the lifetimes of \tcode{x} and \tcode{y} end at +the end of the same full-expression, and +\tcode{x} is initialized before \tcode{y}, then +the destruction of \tcode{y} is sequenced before that of \tcode{x}. If the lifetime of two or more temporaries with lifetimes extending beyond the full-expressions in which they were created ends at the same point, @@ -4784,7 +4992,7 @@ } struct X { int i; }; // now \tcode{X} is a complete type -int arr[10]; // now the type of \tcode{arr} is complete +int arr[10]; // now the type of \tcode{arr} is complete X x; void bar() { @@ -4823,11 +5031,14 @@ Scalar types, trivially copyable class types\iref{class.prop}, arrays of such types, and cv-qualified versions of these types are collectively called \defnadjx{trivially copyable}{types}{type}. -\label{term.trivial.type}% -Scalar types, trivial class types\iref{class.prop}, +\label{term.trivially.relocatable.type}% +Scalar types, trivially relocatable class types\iref{class.prop}, arrays of such types, and cv-qualified versions of these -types are collectively called -\defnadjx{trivial}{types}{type}. +types are collectively called \defnadjx{trivially relocatable}{types}{type}. +\label{term.replaceable.type}% +Cv-unqualified scalar types, replaceable class types\iref{class.prop}, and +arrays of such types are collectively called +\defnadjx{replaceable}{types}{type}. \label{term.standard.layout.type}% Scalar types, standard-layout class types\iref{class.prop}, arrays of such types, and @@ -4850,7 +5061,7 @@ has all of the following properties: \begin{itemize} \item it has a constexpr destructor\iref{dcl.constexpr}, -\item all of its non-static non-variant data members and base classes are of non-volatile literal types, and +\item all of its non-variant non-static data members and base classes are of non-volatile literal types, and \item it \begin{itemize} \item is a closure type\iref{expr.prim.lambda.closure}, @@ -4959,7 +5170,7 @@ the largest value of the corresponding unsigned type. \end{example} -\begin{floattable}{Minimum width}{basic.fundamental.width}{ll} +\begin{floattable}{Minimum width}{basic.fundamental.width}{lc} \topline \lhdr{Type} & \rhdr{Minimum width $N$} \\ \capsep @@ -4980,11 +5191,11 @@ alternative representations of the value specified by the value representation. \begin{note} Padding bits have unspecified value, but cannot cause traps. -In contrast, see ISO C 6.2.6.2. +In contrast, see \IsoC{} 6.2.6.2. \end{note} \begin{note} The signed and unsigned integer types satisfy -the constraints given in ISO C 5.2.4.2.1. +the constraints given in \IsoC{} 5.2.4.2.1. \end{note} Except as specified above, the width of a signed or unsigned integer type is @@ -5144,9 +5355,9 @@ the range of that type is extended to all positive real numbers. \begin{note} Since negative and positive infinity are representable -in ISO/IEC/IEEE 60559 formats, +in \IsoFloatUndated{} formats, all real numbers lie within the range of representable values of -a floating-point type adhering to ISO/IEC/IEEE 60559. +a floating-point type adhering to \IsoFloatUndated{}. \end{note} \pnum @@ -5166,20 +5377,25 @@ A type \cv{}~\keyword{void} is an incomplete type that cannot be completed; such a type has an empty set of values. It is used as the return -type for functions that do not return a value. Any expression can be -explicitly converted to type -\cv{}~\keyword{void}\iref{expr.type.conv,expr.static.cast,expr.cast}. +type for functions that do not return a value. An expression of type \cv{}~\keyword{void} shall -be used only as an expression statement\iref{stmt.expr}, as an operand -of a comma expression\iref{expr.comma}, as a second or third operand -of \tcode{?:}\iref{expr.cond}, as the operand of -\keyword{typeid}, \keyword{noexcept}, or \keyword{decltype}, as -the expression in a \keyword{return} statement\iref{stmt.return} for a function -with the return type \cv{}~\keyword{void}, or as the operand of an explicit conversion -to type \cv{}~\keyword{void}. +be used only as +\begin{itemize} +\item an expression statement\iref{stmt.expr}, +\item the expression in a \keyword{return} statement\iref{stmt.return} +for a function with the return type \cv{}~\keyword{void}, +\item an operand of a comma expression\iref{expr.comma}, +\item the second or third operand of \tcode{?:}\iref{expr.cond}, +\item the operand of a \keyword{typeid} expression\iref{expr.typeid}, +\item the operand of a \keyword{noexcept} operator\iref{expr.unary.noexcept}, +\item the operand of a \keyword{decltype} specifier\iref{dcl.type.decltype}, or +\item the operand of an explicit conversion to type +\cv{}~\keyword{void}\iref{expr.type.conv,expr.static.cast,expr.cast}. +\end{itemize} \pnum -A value of type \tcode{std::nullptr_t} is a null pointer +The types denoted by \cv~\tcode{std::nullptr_t} are distinct types. +A prvalue of type \tcode{std::nullptr_t} is a null pointer constant\iref{conv.ptr}. Such values participate in the pointer and the pointer-to-member conversions\iref{conv.ptr,conv.mem}. \tcode{\keyword{sizeof}(std::nullptr_t)} shall be equal to \tcode{\keyword{sizeof}(\keyword{void}*)}. @@ -5198,9 +5414,9 @@ \pnum If the implementation supports an extended floating-point type\iref{basic.fundamental} whose properties are specified by -the ISO/IEC/IEEE 60559 floating-point interchange format binary16, +the \IsoFloatUndated{} floating-point interchange format binary16, then the \grammarterm{typedef-name} \tcode{std::float16_t} -is defined in the header \libheaderref{stdfloat} and names such a type, +is declared in the header \libheaderref{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT16_T} is defined\iref{cpp.predefined}, and the floating-point literal suffixes \tcode{f16} and \tcode{F16} are supported\iref{lex.fcon}. @@ -5208,40 +5424,40 @@ \pnum If the implementation supports an extended floating-point type whose properties are specified by -the ISO/IEC/IEEE 60559 floating-point interchange format binary32, +the \IsoFloatUndated{} floating-point interchange format binary32, then the \grammarterm{typedef-name} \tcode{std::float32_t} -is defined in the header \libheader{stdfloat} and names such a type, +is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT32_T} is defined, and the floating-point literal suffixes \tcode{f32} and \tcode{F32} are supported. \pnum If the implementation supports an extended floating-point type whose properties are specified by -the ISO/IEC/IEEE 60559 floating-point interchange format binary64, +the \IsoFloatUndated{} floating-point interchange format binary64, then the \grammarterm{typedef-name} \tcode{std::float64_t} -is defined in the header \libheader{stdfloat} and names such a type, +is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT64_T} is defined, and the floating-point literal suffixes \tcode{f64} and \tcode{F64} are supported. \pnum If the implementation supports an extended floating-point type whose properties are specified by -the ISO/IEC/IEEE 60559 floating-point interchange format binary128, +the \IsoFloatUndated{} floating-point interchange format binary128, then the \grammarterm{typedef-name} \tcode{std::float128_t} -is defined in the header \libheader{stdfloat} and names such a type, +is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT128_T} is defined, and the floating-point literal suffixes \tcode{f128} and \tcode{F128} are supported. \pnum If the implementation supports an extended floating-point type -with the properties, as specified by ISO/IEC/IEEE 60559, of +with the properties, as specified by \IsoFloatUndated{}, of radix ($b$) of 2, storage width in bits ($k$) of 16, precision in bits ($p$) of 8, maximum exponent ($emax$) of 127, and exponent field width in bits ($w$) of 8, then the \grammarterm{typedef-name} \tcode{std::bfloat16_t} -is defined in the header \libheader{stdfloat} and names such a type, +is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_BFLOAT16_T} is defined, and the floating-point literal suffixes \tcode{bf16} and \tcode{BF16} are supported. @@ -5250,7 +5466,7 @@ A summary of the parameters for each type is given in \tref{basic.extended.fp}. The precision $p$ includes the implicit 1 bit at the beginning of the significand, so the storage used for the significand is $p-1$ bits. -ISO/IEC/IEEE 60559 does not assign a name for a type +\IsoFloatUndated{} does not assign a name for a type having the parameters specified for \tcode{std::bfloat16_t}. \end{note} \begin{floattable} @@ -5260,7 +5476,7 @@ \chdr{\tcode{float64_t}} & \chdr{\tcode{float128_t}} & \rhdr{\tcode{bfloat16_t}} \\ \capsep -ISO/IEC/IEEE 60559 name & binary16 & binary32 & binary64 & binary128 & \\ +\IsoFloatUndated{} name & binary16 & binary32 & binary64 & binary128 & \\ $k$, storage width in bits & 16 & 32 & 64 & 128 & 16 \\ $p$, precision in bits & 11 & 24 & 53 & 113 & 8 \\ $emax$, maximum exponent & 15 & 127 & 1023 & 16383 & 127 \\ @@ -5271,7 +5487,7 @@ \recommended Any names that the implementation provides for the extended floating-point types described in this subsection -that are in addition to the names defined in the \libheader{stdfloat} header +that are in addition to the names declared in the \libheader{stdfloat} header should be chosen to increase compatibility and interoperability with the interchange types \tcode{_Float16}, \tcode{_Float32}, \tcode{_Float64}, and \tcode{_Float128} @@ -5286,7 +5502,7 @@ \item \defnx{arrays}{type!array} of objects of a given type, \ref{dcl.array}; \item \defnx{functions}{type!function}, which have parameters of given types and return -\keyword{void} or references or objects of a given type, \ref{dcl.fct}; +\keyword{void} or a result of a given type, \ref{dcl.fct}; \item \defnx{pointers}{type!pointer} to \cv{}~\keyword{void} or objects or functions (including static members of classes) of a given type, \ref{dcl.ptr}; @@ -5302,9 +5518,8 @@ \end{itemize} \item -\defnx{classes}{class} containing a sequence of objects of various types\iref{class}, -a set of types, enumerations and functions for -manipulating these objects\iref{class.mfct}, and a set of restrictions +\defnx{classes}{class} containing a sequence of class members\iref{class,class.mem}, +and a set of restrictions on the access to these entities\iref{class.access}; \item @@ -5388,17 +5603,13 @@ is not considered to point to an unrelated object of the object's type, even if the unrelated object is located at that address. -A pointer value becomes invalid -when the storage it denotes -reaches the end of its storage duration; -see \ref{basic.stc}. \end{note} For purposes of pointer arithmetic\iref{expr.add} and comparison\iref{expr.rel,expr.eq}, a pointer past the end of the last element of an array \tcode{x} of $n$ elements is considered to be equivalent to -a pointer to a hypothetical array element $n$ of \tcode{x} and +a pointer to a hypothetical array element $n$ of \tcode{x}, and an object of type \tcode{T} that is not an array element is considered to belong to an array with one element of type \tcode{T}. The value representation of @@ -5413,7 +5624,32 @@ \end{note} \pnum -Two objects \placeholder{a} and \placeholder{b} are \defn{pointer-interconvertible} if: +A pointer value $P$ is +\indextext{value!valid in the context of an evaluation}% +\defn{valid in the context of} an evaluation $E$ +if $P$ is a pointer to function or a null pointer value, or +if it is a pointer to or past the end of an object $O$ and +$E$ happens before the end of the duration of the region of storage for $O$. +If a pointer value $P$ is used in an evaluation $E$ and +$P$ is not valid in the context of $E$, +then the behavior is undefined if $E$ is +an indirection\iref{expr.unary.op} or +an invocation of a deallocation function\iref{basic.stc.dynamic.deallocation}, +and \impldef{invalid pointer value in the context of an evaluation} otherwise. +\begin{footnote} +Some implementations might define that +copying such a pointer value causes a system-generated runtime fault. +\end{footnote} +\begin{note} +$P$ can be valid in the context of $E$ even +if it points to a type unrelated to that of $O$ or +if $O$ is not within its lifetime, +although further restrictions apply +to such pointer values\iref{basic.life, basic.lval, expr.add}. +\end{note} + +\pnum +Two objects \placeholder{a} and \placeholder{b} are \defn{pointer-interconvertible} if \begin{itemize} \item they are the same object, or @@ -5653,6 +5889,15 @@ An extended floating-point type with the same set of values as more than one cv-unqualified standard floating-point type has a rank equal to the rank of \keyword{double}. +\begin{tailnote} +The treatment of \tcode{std::float64_t} differs from +that of the analogous \tcode{_Float64} in C, +for example on platforms where all of +\tcode{\keyword{long} \keyword{double}}, +\keyword{double}, and +\tcode{std::float64_t} +have the same set of values (see \IsoCUndated{}:2024 H.4.2). +\end{tailnote} \end{itemize} \begin{note} The conversion ranks of floating-point types \tcode{T1} and \tcode{T2} @@ -5771,13 +6016,16 @@ \item an immediate invocation\iref{expr.const}, \item -an \grammarterm{init-declarator}\iref{dcl.decl} or +an \grammarterm{init-declarator}\iref{dcl.decl} +(including such introduced by a structured binding\iref{dcl.struct.bind}) or a \grammarterm{mem-initializer}\iref{class.base.init}, including the constituent expressions of the initializer, \item an invocation of a destructor generated at the end of the lifetime of an object other than a temporary object\iref{class.temporary} -whose lifetime has not been extended, or +whose lifetime has not been extended, +\item +the predicate of a contract assertion\iref{basic.contract}, or \item an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression. @@ -5841,7 +6089,7 @@ determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects. When a call to a library I/O function -returns or an access through a volatile glvalue is evaluated the side +returns or an access through a volatile glvalue is evaluated, the side effect is considered complete, even though some external actions implied by the call (such as the I/O itself) or by the \keyword{volatile} access may not have completed yet. @@ -5903,13 +6151,30 @@ \end{note} The value computations of the operands of an operator are sequenced before the value computation of the result of the -operator. If a +operator. +The behavior is undefined if +\begin{itemize} +\item \indextext{side effects}% -side effect on a memory location\iref{intro.memory} is unsequenced -relative to either another side effect on the same memory location or +a side effect on a memory location\iref{intro.memory} or +\item +starting or ending the lifetime of an object in a memory location +\end{itemize} +is unsequenced relative to +\begin{itemize} +\item +another side effect on the same memory location, +\item +starting or ending the lifetime of an object occupying storage that +overlaps with the memory location, or +\item a value computation using the value of any object in the same memory location, -and they are not potentially concurrent\iref{intro.multithread}, -the behavior is undefined. +\end{itemize} +and the two evaluations are not potentially concurrent\iref{intro.multithread}. +\begin{note} +Starting the lifetime of an object in a memory location can end the lifetime of +objects in other memory locations\iref{basic.life}. +\end{note} \begin{note} The next subclause imposes similar, but more complex restrictions on potentially concurrent computations. @@ -5923,20 +6188,35 @@ i = i++ + 1; // the value of \tcode{i} is incremented i = i++ + i; // undefined behavior i = i + 1; // the value of \tcode{i} is incremented + + union U { int x, y; } u; + (u.x = 1, 0) + (u.y = 2, 0); // undefined behavior } \end{codeblock} \end{example} \pnum -When invoking a function (whether or not the function is inline), +When invoking a function \placeholder{f} (whether or not the function is inline), every argument expression and -the postfix expression designating the called function -are sequenced before every expression or statement -in the body of the called function. -For each function invocation or -evaluation of an \grammarterm{await-expression} \placeholder{F}, -each evaluation that does not occur within \placeholder{F} but -is evaluated on the same thread and as part of the same signal handler (if any) +the postfix expression designating \placeholder{f} +are sequenced before +every precondition assertion of \placeholder{f}\iref{dcl.contract.func}, +which in turn are sequenced before +every expression or statement +in the body of \placeholder{f}, +which in turn are sequenced before +every postcondition assertion of \placeholder{f}. + +\pnum +For each +\begin{itemize} +\item function invocation, +\item evaluation of an \grammarterm{await-expression}\iref{expr.await}, or +\item evaluation of a \grammarterm{throw-expression}\iref{expr.throw} +\end{itemize} +\placeholder{F}, +each evaluation that does not occur within \placeholder{F} +but is evaluated on the same thread and as part of the same signal handler (if any) is either sequenced before all evaluations that occur within \placeholder{F} or sequenced after all evaluations that occur within \placeholder{F}; \begin{footnote} @@ -5949,6 +6229,7 @@ prior to the next suspension (if any) are considered to occur within \placeholder{F}. +\pnum Several contexts in \Cpp{} cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. @@ -5958,6 +6239,8 @@ invocation of a conversion function\iref{class.conv.fct} can arise in contexts in which no function call syntax appears. \end{example} + +\pnum The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, regardless of the syntax of the expression that calls the function.% @@ -6033,16 +6316,32 @@ \end{note} \pnum -Two expression evaluations \defn{conflict} if one of them modifies a memory -location\iref{intro.memory} and the other one reads or modifies the same -memory location. +Two expression evaluations \defn{conflict} if one of them +\begin{itemize} +\item +modifies\iref{defns.access} a memory location\iref{intro.memory} or +\item +starts or ends the lifetime of an object in a memory location +\end{itemize} +and the other one +\begin{itemize} +\item +reads or modifies the same memory location or +\item +starts or ends the lifetime of an object occupying storage that +overlaps with the memory location. +\end{itemize} +\begin{note} +A modification can still conflict +even if it does not alter the value of any bits. +\end{note} \pnum The library defines a number of atomic operations\iref{atomics} and operations on mutexes\iref{thread} that are specially identified as synchronization operations. These operations play a special role in making assignments in one thread visible to another. A synchronization operation on one -or more memory locations is either a consume operation, an acquire operation, a +or more memory locations is either an acquire operation, a release operation, or both an acquire and release operation. A synchronization operation without an associated memory location is a fence and can be either an acquire fence, a release fence, or both an acquire and release fence. In @@ -6098,122 +6397,17 @@ the value written'' by the last mutex release. \end{note} -\pnum -An evaluation $A$ \defn{carries a dependency} to an evaluation $B$ if -\begin{itemize} -\item -the value of $A$ is used as an operand of $B$, unless: -\begin{itemize} -\item -$B$ is an invocation of any specialization of -\tcode{std::kill_dependency}\iref{atomics.order}, or -\item -$A$ is the left operand of a built-in logical \logop{and} (\tcode{\&\&}, -see~\ref{expr.log.and}) or logical \logop{or} (\tcode{||}, see~\ref{expr.log.or}) -operator, or -\item -$A$ is the left operand of a conditional (\tcode{?:}, see~\ref{expr.cond}) -operator, or -\item -$A$ is the left operand of the built-in comma (\tcode{,}) -operator\iref{expr.comma}; \end{itemize} or -\item -$A$ writes a scalar object or bit-field $M$, $B$ reads the value -written by $A$ from $M$, and $A$ is sequenced before $B$, or -\item -for some evaluation $X$, $A$ carries a dependency to $X$, and -$X$ carries a dependency to $B$. -\end{itemize} -\begin{note} -``Carries a dependency to'' is a subset of ``is sequenced before'', -and is similarly strictly intra-thread. -\end{note} - -\pnum -An evaluation $A$ is \defn{dependency-ordered before} an evaluation -$B$ if -\begin{itemize} -\item -$A$ performs a release operation on an atomic object $M$, and, in -another thread, $B$ performs a consume operation on $M$ and reads -the value written by $A$, or - -\item -for some evaluation $X$, $A$ is dependency-ordered before $X$ and -$X$ carries a dependency to $B$. - -\end{itemize} -\begin{note} -The relation ``is dependency-ordered before'' is analogous to -``synchronizes with'', but uses release/consume in place of release/acquire. -\end{note} - -\pnum -An evaluation $A$ \defn{inter-thread happens before} an evaluation $B$ -if -\begin{itemize} -\item - $A$ synchronizes with $B$, or -\item - $A$ is dependency-ordered before $B$, or -\item - for some evaluation $X$ - \begin{itemize} - \item - $A$ synchronizes with $X$ and $X$ - is sequenced before $B$, or - \item - $A$ is sequenced before $X$ and $X$ - inter-thread happens before $B$, or - \item - $A$ inter-thread happens before $X$ and $X$ - inter-thread happens before $B$. - \end{itemize} -\end{itemize} -\begin{note} -The ``inter-thread happens before'' relation describes arbitrary -concatenations of ``sequenced before'', ``synchronizes with'' and -``dependency-ordered before'' relationships, with two exceptions. The first -exception is that a concatenation is not permitted to end with -``dependency-ordered before'' followed by ``sequenced before''. The reason for -this limitation is that a consume operation participating in a -``dependency-ordered before'' relationship provides ordering only with respect -to operations to which this consume operation actually carries a dependency. The -reason that this limitation applies only to the end of such a concatenation is -that any subsequent release operation will provide the required ordering for a -prior consume operation. The second exception is that a concatenation is not -permitted to consist entirely of ``sequenced before''. The reasons for this -limitation are (1) to permit ``inter-thread happens before'' to be transitively -closed and (2) the ``happens before'' relation, defined below, provides for -relationships consisting entirely of ``sequenced before''. -\end{note} - \pnum An evaluation $A$ \defn{happens before} an evaluation $B$ -(or, equivalently, $B$ \defn{happens after} $A$) if: -\begin{itemize} -\item $A$ is sequenced before $B$, or -\item $A$ inter-thread happens before $B$. -\end{itemize} -The implementation shall ensure that no program execution demonstrates a cycle -in the ``happens before'' relation. -\begin{note} -This cycle would otherwise be -possible only through the use of consume operations. -\end{note} - -\pnum -An evaluation $A$ \defn{simply happens before} an evaluation $B$ +(or, equivalently, $B$ happens after $A$) if either \begin{itemize} \item $A$ is sequenced before $B$, or \item $A$ synchronizes with $B$, or -\item $A$ simply happens before $X$ and -$X$ simply happens before $B$. +\item $A$ happens before $X$ and $X$ happens before $B$. \end{itemize} \begin{note} -In the absence of consume operations, -the happens before and simply happens before relations are identical. +An evaluation does not happen before itself. \end{note} \pnum @@ -6226,7 +6420,7 @@ sequentially consistent atomic operations\iref{atomics.order}, or \item there are evaluations $B$ and $C$ such that $A$ is sequenced before $B$, -$B$ simply happens before $C$, and +$B$ happens before $C$, and $C$ is sequenced before $D$, or \item there is an evaluation $B$ such that $A$ strongly happens before $B$, and @@ -6235,7 +6429,7 @@ \begin{note} Informally, if $A$ strongly happens before $B$, then $A$ appears to be evaluated before $B$ -in all contexts. Strongly happens before excludes consume operations. +in all contexts. \end{note} \pnum @@ -6262,7 +6456,7 @@ \begin{note} This states that operations on ordinary objects are not visibly reordered. This is not actually detectable -without data races, but it is necessary to ensure that data races, as defined +without data races, but is needed to ensure that data races, as defined below, and with suitable restrictions on the use of atomics, correspond to data races in a simple interleaved (sequentially consistent) execution. \end{note} @@ -6373,12 +6567,13 @@ However, this applies only to data-race-free programs, and data-race-free programs cannot observe most program transformations that do not change single-threaded program semantics. In fact, most single-threaded program -transformations continue to be allowed, since any program that behaves +transformations remain possible, since any program that behaves differently as a result has undefined behavior. \end{note} \pnum -Two accesses to the same object of type \tcode{\keyword{volatile} std::sig_atomic_t} do not +Two accesses to the same non-bit-field object +of type \tcode{\keyword{volatile} std::sig_atomic_t} do not result in a data race if both occur in the same thread, even if one or more occurs in a signal handler. For each signal handler invocation, evaluations performed by the thread invoking a signal handler can be divided into two @@ -6404,8 +6599,8 @@ \pnum \begin{note} -Transformations that introduce a speculative read of a potentially -shared memory location might not preserve the semantics of the \Cpp{} program as +It is possible that transformations that introduce a speculative read of a potentially +shared memory location do not preserve the semantics of the \Cpp{} program as defined in this document, since they potentially introduce a data race. However, they are typically valid in the context of an optimizing compiler that targets a specific machine with well-defined semantics for data races. They would be @@ -6420,13 +6615,18 @@ following: \begin{itemize} \item terminate, +\item invoke the function \tcode{std::this_thread::yield}\iref{thread.thread.this}, \item make a call to a library I/O function, -\item perform an access through a volatile glvalue, or -\item perform a synchronization operation or an atomic operation. +\item perform an access through a volatile glvalue, +\item perform a synchronization operation or an atomic operation, or +\item continue execution of a trivial infinite loop\iref{stmt.iter.general}. \end{itemize} \begin{note} -This is intended to allow compiler transformations such as removal of -empty loops, even when termination cannot be proven. +This is intended to allow compiler transformations +such as removal, merging, and reordering of empty loops, +even when termination cannot be proven. +An affordance is made for trivial infinite loops, +which cannot be removed nor reordered. \end{note} \pnum @@ -6510,7 +6710,7 @@ the implementation ensures that the thread will eventually make progress for as long as it has not terminated. \begin{note} -This is required regardless of whether or not other threads of execution (if any) +This applies regardless of whether or not other threads of execution (if any) have been or are making progress. To eventually fulfill this requirement means that this will happen in an unspecified but finite amount of time. \end{note} @@ -6667,7 +6867,7 @@ \tcode{argv[0]} through \tcode{argv[argc-1]} as pointers to the initial characters of null-terminated multibyte strings (\ntmbs{}s)\iref{multibyte.strings} and \tcode{argv[0]} shall be the pointer to -the initial character of a \ntmbs{} that represents the name used to +the initial character of an \ntmbs{} that represents the name used to invoke the program or \tcode{""}. The value of \tcode{argc} shall be non-negative. The value of \tcode{argv[argc]} shall be 0. @@ -6675,8 +6875,7 @@ Any further (optional) parameters should be added after \tcode{argv}. \pnum -The function \tcode{main} shall not be used within -a program. +The function \tcode{main} shall not be named by an expression. \indextext{\idxcode{main} function!implementation-defined linkage of}% The linkage\iref{basic.link} of \tcode{main} is \impldef{linkage of \tcode{main}}. A program that defines \tcode{main} as @@ -6722,9 +6921,10 @@ \pnum \indextext{termination!program}% \indextext{\idxcode{main} function!return from}% -A \keyword{return} statement\iref{stmt.return} in \tcode{main} has the effect of leaving the main -function (destroying any objects with automatic storage duration) and -calling \tcode{std::exit} with the return value as the argument. +A \keyword{return} statement\iref{stmt.return} in \tcode{main} has the effect of leaving the \tcode{main} +function (destroying any objects with automatic storage duration +and evaluating any postcondition assertions of \tcode{main}) +and calling \tcode{std::exit} with the return value as the argument. If control flows off the end of the \grammarterm{compound-statement} of \tcode{main}, the effect is equivalent to a \keyword{return} with operand \tcode{0} @@ -6744,7 +6944,7 @@ \pnum \indextext{initialization!constant}% \defnx{Constant initialization}{constant initialization} is performed -if a variable or temporary object with static or thread storage duration +if a variable with static or thread storage duration is constant-initialized\iref{expr.const}. \indextext{initialization!zero-initialization}% If constant initialization is not performed, a variable with static @@ -7056,3 +7256,442 @@ the functions passed to \tcode{std::atexit()} or \tcode{std::at_quick_exit()}.% \indextext{program!termination|)} \indextext{program execution|)} + +\rSec1[basic.contract]{Contract assertions}% +\indextext{contract assertion|(}% + +\rSec2[basic.contract.general]{General}% + +\pnum +\defnx{Contract assertions}{contract assertion} +allow the programmer to specify +properties of the state of the program +that are expected to hold at +certain points during execution. +Contract assertions are introduced by +\grammarterm{precondition-specifier}s, +\grammarterm{postcondition-specifier}s\iref{dcl.contract.func}, and +\grammarterm{assertion-statement}s\iref{stmt.contract.assert}. + +\pnum +Each contract assertion has a \defnadjx{contract-assertion}{predicate}{predicate}, +which is an expression of type \tcode{bool}. + +\begin{note} +The value of the predicate is used to identify program states that are +expected. +\end{note} + +\pnum +An invocation of the macro \tcode{va_start}\iref{cstdarg.syn} +shall not be a subexpression +of the predicate of a contract assertion, +no diagnostic required. + +\pnum +\begin{note} +Within the predicate of a contract assertion, +\grammarterm{id-expression}s referring to +variables declared outside the contract assertion +are \keyword{const}\iref{expr.prim.id.unqual}, +\tcode{this} is a pointer to \keyword{const}\iref{expr.prim.this}, +and the result object can be named +if a \grammarterm{result-name-introducer}\iref{dcl.contract.res} has been specified. +\end{note} + +\rSec2[basic.contract.eval]{Evaluation} + +\pnum +\indexdefn{evaluation semantics|see{contract evaluation semantics}}% +\indexdefn{checking semantics|see{contract evaluation semantics!checking}}% +\indexdefn{terminating semantics|see{contract evaluation semantics!terminating}}% +An evaluation of a contract assertion +uses one of the following four \defn{evaluation semantics}: +\defnx{ignore}{contract evaluation semantics!ignore}, +\defnx{observe}{contract evaluation semantics!observe}, +\defnx{enforce}{contract evaluation semantics!enforce}, or +\defnx{quick-enforce}{contract evaluation semantics!quick-enforce}. +Observe, enforce, and quick-enforce are \defnx{checking semantics}{contract evaluation semantics!checking}; +enforce and quick-enforce are \defnx{terminating semantics}{contract evaluation semantics!terminating}. + +\pnum +It is +\impldef{evaluation semantic used for the evaluation of a contract assertion} +which evaluation semantic is used +for any given evaluation of a contract assertion. +\begin{note} +The range and flexibility of available choices of +evaluation semantics depends on the implementation +and need not allow all four evaluation semantics as possibilities. +The evaluation semantics can differ +for different evaluations of the same contract assertion, +including evaluations during constant evaluation. +\end{note} + +\pnum +\recommended +An implementation should provide +the option to translate a program +such that all evaluations of contract assertions use the ignore semantic +as well as +the option to translate a program +such that all evaluations of contract assertions use the enforce semantic. +By default, +evaluations of contract assertions should use the enforce semantic. + +\pnum +The evaluation of a contract assertion using the ignore semantic has no effect. +\begin{note} +The predicate is potentially evaluated\iref{basic.def.odr}, +but not evaluated. +\end{note} + +\pnum +The evaluation $A$ of a contract assertion +using a checking semantic +determines the value of the predicate. +It is unspecified +whether the predicate is evaluated. +Let $B$ be the value that would result from evaluating the predicate. +\begin{note} +To determine whether a predicate would evaluate +to \keyword{true} or \keyword{false}, +an alternative evaluation +that produces the same value as the predicate +but has no side effects +can occur. +\begin{example} +\begin{codeblock} +struct S { + mutable int g = 5; +} s; +void f() + pre(( s.g++, false )); // \#1 +void g() +{ + f(); // Increment of \tcode{s.g} might not occur, even if \#1 uses a checking semantic. +} +\end{codeblock} +\end{example} +\end{note} + +\pnum +There is an observable checkpoint\iref{intro.abstract} $C$ +that happens before $A$ +such that any other operation $O$ +that happens before $A$ +also happens before $C$. + +\pnum +A \defn{contract violation} occurs when +\begin{itemize} +\item +$B$ is \keyword{false}, +\item +the evaluation of the predicate +exits via an exception, or +\item +the evaluation of the predicate +is performed in a context that is +manifestly constant-evaluated\iref{expr.const} +and the predicate +is not a core constant expression. +\end{itemize} + +\begin{note} +If $B$ is \keyword{true}, +no contract violation occurs and +control flow continues normally +after the point of evaluation of the contract assertion. +The evaluation of the predicate +can fail to produce a value +without causing a contract violation, +for example, +by calling \tcode{longjmp}\iref{csetjmp.syn} +or terminating the program. +\end{note} + +\pnum +\indexdefn{contract evaluation semantics!terminating}% +If a contract violation occurs +in a context that is manifestly constant-evaluated\iref{expr.const}, +and the evaluation semantic is +a terminating semantic, +the program is ill-formed. + +\begin{note} +A diagnostic is produced +if the evaluation semantic is observe\iref{intro.compliance}. +\end{note} + +\begin{note} +Different evaluation semantics +chosen for the same contract assertion +in different translation units +can result in +violations of the one-definition rule\iref{basic.def.odr} +when a contract assertion has side effects +that alter the value produced by a constant expression. +\begin{example} +\begin{codeblock} +constexpr int f(int i) +{ + contract_assert((++const_cast(i), true)); + return i; +} +inline void g() +{ + int a[f(1)]; // size dependent on the evaluation semantic of \tcode{contract_assert} above +} +\end{codeblock} +\end{example} +\end{note} + +\pnum +When the program is \defn{contract-terminated}, +it is +\impldef{method by which contract termination occurs} +(depending on context) whether +\begin{itemize} +\item +\tcode{std::terminate} is called, +\item +\tcode{std::abort} is called, or +\item +execution is terminated. + +\begin{note} +No further execution steps occur\iref{intro.progress}. +\end{note} +\end{itemize} + +\begin{note} +Performing the actions of +\tcode{std::terminate} or \tcode{std::abort} +without actually making a library call +is a conforming implementation of +contract-termination\iref{intro.abstract}. +\end{note} + +\pnum +\indextext{contract evaluation semantics!enforce}% +\indextext{contract evaluation semantics!quick-enforce}% +If a contract violation occurs +in a context that is not manifestly constant-evaluated +and the evaluation semantic is quick-enforce, +the program is contract-terminated. + +\pnum +\indextext{\idxcode{contract_violation}}% +\indextext{contract evaluation semantics!enforce}% +\indextext{contract evaluation semantics!observe}% +\indexlibraryglobal{contract_violation}% +If a contract violation occurs +in a context that is not manifestly constant-evaluated +and the evaluation semantic is enforce or observe, +the contract-violation handler\iref{basic.contract.handler} +is invoked with an lvalue referring to +an object \tcode{v} +of type \tcode{const std::contracts::contract_violation}\iref{support.contract.violation} +containing information about the contract violation. +Storage for \tcode{v} +is allocated in an unspecified manner +except as noted in \ref{basic.stc.dynamic.allocation}. +The lifetime of \tcode{v} +persists for the duration +of the invocation of the contract-violation handler. + +\pnum +If the contract violation occurred +because the evaluation of the predicate +exited via an exception, +the contract-violation handler is invoked +from within an active implicit handler +for that exception\iref{except.handle}. +If the contract-violation handler +returns normally +and the evaluation semantic is observe, +that implicit handler +is no longer considered active. + +\begin{note} +The exception can be inspected or rethrown within the contract-violation handler. +\end{note} + +\pnum +\indextext{contract evaluation semantics!enforce}% +If the contract-violation handler +returns normally +and the evaluation semantic is enforce, +the program is contract-terminated; +if violation occurred +as the result of an uncaught exception +from the evaluation of the predicate, +the implicit handler +remains active when contract termination occurs. + +\pnum +\indextext{contract evaluation semantics!observe}% +\begin{note} +If the contract-violation handler +returns normally +and the evaluation semantic is observe, +control flow continues normally +after the point of evaluation of the contract assertion. +\end{note} + +\pnum +There is an observable checkpoint\iref{intro.abstract} $C$ +that happens after the contract-violation handler returns normally +such that any other operation $O$ +that happens after the contract-violation handler returns +also happens after $C$. + +\pnum +\begin{note} +The terminating semantics terminate the program +if execution would otherwise continue normally +past a contract violation: +the enforce semantic provides the opportunity to +log information about the contract violation +before terminating the program +or to throw an exception to avoid termination, +and the quick-enforce semantic is intended +to terminate the program as soon as possible +as well as +to minimize the impact of contract checks +on the generated code size. +Conversely, +the observe semantic +provides the opportunity to +log information about the contract violation +without having to terminate the program. +\end{note} + +\pnum +If a contract-violation handler +invoked from the evaluation of a function contract assertion\iref{dcl.contract.func} +exits via an exception, +the behavior is as if +the function body exits via that same exception. +\begin{note} +A \grammarterm{function-try-block}\iref{except.pre} +is the function body when present +and thus does not +have an opportunity to catch the exception. +If the function +has a non-throwing exception specification, +the function \tcode{std::terminate} is invoked\iref{except.terminate}. +\end{note} + +\begin{note} +If a contract-violation handler +invoked from an \grammarterm{assertion-statement}\iref{stmt.contract.assert}) +exits via an exception, +the search for a handler +continues from the execution of that statement. +\end{note} + +\pnum +To \defn{evaluate in sequence} a list $R$ of contract assertions: +\begin{itemize} +\item +Construct a list of contract assertions $S$ such that +\begin{itemize} +\item +all elements of $R$ are in $S$, +\item +each element of $R$ +may be repeated an +\impldef{maximum number of repeated evaluations of a contract assertion} +number of times +within $S$, and +\item +if a contract assertion $A$ +precedes another contract assertion $B$ +in $R$, +then the +first occurrence of $A$ +precedes the first occurrence of $B$ +in $S$. +\end{itemize} +\item +Evaluate each element of $S$ such that, +if a contract assertion $A$ +precedes a contract assertion $B$ +in $S$, +then the evaluation of $A$ +is sequenced before +the evaluation of $B$. +\end{itemize} + +\begin{example} +\begin{codeblock} +void f(int i) +{ + contract_assert(i > 0); // \#1 + contract_assert(i < 10); // \#2 + // valid sequence of evaluations: \#1 \#2 + // valid sequence of evaluations: \#1 \#1 \#2 \#2 + // valid sequence of evaluations: \#1 \#2 \#1 \#2 + // valid sequence of evaluations: \#1 \#2 \#2 \#1 + // invalid sequence of evaluations: \#2 \#1 +} +\end{codeblock} +\end{example} + +\pnum +\recommended +An implementation should +provide an option to perform +a specified number of repeated evaluations +for contract assertions. +By default, +no repeated evaluations should be performed. + +\rSec2[basic.contract.handler]{Contract-violation handler} + +\pnum +\indextext{\idxcode{contract_violation}}% +\indexlibraryglobal{contract_violation}% +The \defn{contract-violation handler} +of a program is a function named +\tcode{::handle_contract_violation}. +The contract-violation handler +shall have a single parameter +of type +``lvalue reference to \keyword{const} \tcode{std::\-contracts::\-contract_violation}'' +and shall return \tcode{void}. +The contract-violation handler +may have a non-throwing exception specification. +The implementation +shall provide a definition of the contract-violation handler, +called the \defnadj{default}{contract-violation handler}. +\begin{note} +No declaration +for the default contract-violation handler +is provided by +any standard library header. +\end{note} + +\pnum +\recommended +The default contract-violation handler +should produce diagnostic output +that suitably formats the most relevant contents +of the \tcode{std::contracts::contract_violation} object, +rate-limited for potentially repeated violations +of observed contract assertions, +and then return normally. + +\pnum +It is +\impldef{replaceability of the contract-violation handler} +whether the contract-violation handler +is replaceable\iref{dcl.fct.def.replace}. +If the contract-violation handler +is not replaceable, +a declaration of a replacement function for the contract-violation handler +is ill-formed, no diagnostic required. + +\indextext{contract assertion|)} diff --git a/source/classes.tex b/source/classes.tex index a90967fe86..3a80fc1528 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -36,7 +36,7 @@ \begin{bnf} \nontermdef{class-head}\br - class-key \opt{attribute-specifier-seq} class-head-name \opt{class-virt-specifier} \opt{base-clause}\br + class-key \opt{attribute-specifier-seq} class-head-name \opt{class-property-specifier-seq} \opt{base-clause}\br class-key \opt{attribute-specifier-seq} \opt{base-clause} \end{bnf} @@ -46,8 +46,15 @@ \end{bnf} \begin{bnf} -\nontermdef{class-virt-specifier}\br - \keyword{final} +\nontermdef{class-property-specifier-seq}\br + class-property-specifier \opt{class-property-specifier-seq} +\end{bnf} + +\begin{bnf} +\nontermdef{class-property-specifier}\br + \keyword{final}\br + \keyword{trivially_relocatable_if_eligible}\br + \keyword{replaceable_if_eligible} \end{bnf} \begin{bnf} @@ -72,7 +79,8 @@ it is not looked up, and the \grammarterm{class-specifier} introduces it. \pnum -The +\indextext{component name}% +The component name of the \grammarterm{class-name} is also bound in the scope of the class (template) itself; this is known as the \defn{injected-class-name}. For purposes of access checking, the injected-class-name is treated as @@ -119,12 +127,13 @@ \end{note} \pnum -If a class is marked with the \grammarterm{class-virt-specifier} \tcode{final} and it appears -as a \grammarterm{class-or-decltype} in a \grammarterm{base-clause}\iref{class.derived}, -the program is ill-formed. Whenever a -\grammarterm{class-key} is followed by a \grammarterm{class-head-name}, the -\grammarterm{identifier} \tcode{final}, and a colon or left brace, \tcode{final} is -interpreted as a \grammarterm{class-virt-specifier}. +Each \grammarterm{class-property-specifier} shall appear at most once +within a single \grammarterm{class-property-specifier-seq}. +Whenever a \grammarterm{class-key} is followed +by a \grammarterm{class-head-name}, +the identifier \tcode{final}, \tcode{trivially_relocatable_if_eligible}, +or \tcode{replaceable_if_eligible}, and a colon or left brace, +the identifier is interpreted as a \grammarterm{class-property-specifier}. \begin{example} \begin{codeblock} struct A; @@ -133,12 +142,19 @@ struct X { struct C { constexpr operator int() { return 5; } }; - struct B final : C{}; // OK, definition of nested class \tcode{B}, - // not declaration of a bit-field member \tcode{final} + struct B trivially_relocatable_if_eligible : C{}; + // OK, definition of nested class \tcode{B}, + // not declaration of a bit-field member + // \tcode{trivially_relocatable_if_eligible} }; \end{codeblock} \end{example} +\pnum +If a class is marked with the \grammarterm{class-property-specifier} +\tcode{final} and that class appears as a \grammarterm{class-or-decltype} +in a \grammarterm{base-clause}\iref{class.derived}, the program is ill-formed. + \pnum \begin{note} Complete objects of class type have nonzero size. @@ -149,7 +165,7 @@ \pnum \begin{note} -Class objects can be assigned\iref{over.ass,class.copy.assign}, +Class objects can be assigned\iref{over.assign,class.copy.assign}, passed as arguments to functions\iref{dcl.init,class.copy.ctor}, and returned by functions (except objects of classes for which copying or moving has been restricted; see~\ref{dcl.fct.def.delete} and \ref{class.access}). @@ -172,12 +188,84 @@ \end{itemize} \pnum -A \defnadj{trivial}{class} is a class that is trivially copyable and -has one or more eligible default constructors\iref{class.default.ctor}, -all of which are trivial. +A class \tcode{C} is \defn{default-movable} if + +\begin{itemize} +\item overload resolution for direct-initializing an object of type \tcode{C} +from an xvalue of type \tcode{C} selects a constructor that is a direct member +of \tcode{C} and is neither user-provided nor deleted, + +\item overload resolution for assigning to an lvalue of type \tcode{C} from an +xvalue of type \tcode{C} selects an assignment operator function that is a +direct member of \tcode{C} and is neither user-provided nor deleted, and + +\item \tcode{C} has a destructor that is neither user-provided nor deleted. +\end{itemize} + +\pnum +A class is \defn{eligible for trivial relocation} unless it +\begin{itemize} +\item has any virtual base classes, +\item has a base class that is not a trivially relocatable class, +\item has a non-static data member of an object type that is not of a +trivially relocatable type, or + +\item has a deleted destructor, +\end{itemize} +except that it is \impldef{whether an otherwise-eligible union having one or +more subobjects of polymorphic class type is eligible for trivial relocation} +whether an otherwise-eligible union having one or more subobjects of +polymorphic class type is eligible for trivial relocation. + +\pnum +A class \tcode{C} is a \defnadj{trivially relocatable}{class} +if it is eligible for trivial relocation and +\begin{itemize} +\item has the \tcode{trivially_relocatable_if_eligible} \grammarterm{class-property-specifier}, +\item is a union with no user-declared special member functions, or +\item is default-movable. +\end{itemize} + +\pnum \begin{note} -In particular, a trivially copyable or trivial class does not have -virtual functions or virtual base classes. +A class with const-qualified or reference non-static data members can be +trivially relocatable. +\end{note} + +\pnum +A class \tcode{C} is \defn{eligible for replacement} unless +\begin{itemize} +\item it has a base class that is not a replaceable class, +\item it has a non-static data member that is not of a replaceable type, +\item overload resolution fails or selects a deleted constructor when +direct-initializing an object of type \tcode{C} from an xvalue of type +\tcode{C}\iref{dcl.init.general}, + +\item overload resolution fails or selects a deleted assignment operator +function when assigning to an lvalue of type \tcode{C} from an xvalue of type +\tcode{C} \iref{expr.assign,over.assign}), or + +\item it has a deleted destructor. +\end{itemize} + +\pnum +A class \tcode{C} is a \defnadj{replaceable}{class} if it is +eligible for replacement and +\begin{itemize} +\item has the \tcode{replaceable_if_eligible} \grammarterm{class-property-specifier}, +\item is a union with no user-declared special member functions, or +\item is default-movable. +\end{itemize} + +\pnum +\begin{note} +Accessibility of the special member functions is not considered when +establishing trivial relocatability or replaceability. +\end{note} + +\pnum +\begin{note} +Not all trivially copyable classes are trivially relocatable or replaceable. \end{note} \pnum @@ -265,31 +353,31 @@ \begin{note} Standard-layout classes are useful for communicating with code written in other programming languages. Their layout is specified -in~\ref{class.mem}. +in~\ref{class.mem.general} and~\ref{expr.rel}. \end{note} \pnum \begin{example} \begin{codeblock} -struct N { // neither trivial nor standard-layout +struct N { // neither trivially copyable nor standard-layout int i; int j; virtual ~N(); }; -struct T { // trivial but not standard-layout +struct T { // trivially copyable but not standard-layout int i; private: int j; }; -struct SL { // standard-layout but not trivial +struct SL { // standard-layout but not trivially copyable int i; int j; ~SL(); }; -struct POD { // both trivial and standard-layout +struct POD { // both trivially copyable and standard-layout int i; int j; }; @@ -430,7 +518,8 @@ \begin{note} The declaration of a class name takes effect immediately after the \grammarterm{identifier} is seen in the class definition or -\grammarterm{elaborated-type-specifier}. For example, +\grammarterm{elaborated-type-specifier}. +\begin{example} \begin{codeblock} class A * A; \end{codeblock} @@ -438,6 +527,7 @@ it as the name of a pointer to an object of that class. This means that the elaborated form \keyword{class} \tcode{A} must be used to refer to the class. Such artistry with names can be confusing and is best avoided. +\end{example} \end{note} \pnum @@ -461,6 +551,7 @@ \nontermdef{member-declaration}\br \opt{attribute-specifier-seq} \opt{decl-specifier-seq} \opt{member-declarator-list} \terminal{;}\br function-definition\br + friend-type-declaration\br using-declaration\br using-enum-declaration\br static_assert-declaration\br @@ -480,16 +571,15 @@ \begin{bnf} \nontermdef{member-declarator}\br - declarator \opt{virt-specifier-seq} \opt{pure-specifier}\br - declarator requires-clause\br - declarator \opt{brace-or-equal-initializer}\br + declarator \opt{virt-specifier-seq} \opt{function-contract-specifier-seq} \opt{pure-specifier}\br + declarator requires-clause \opt{function-contract-specifier-seq}\br + declarator brace-or-equal-initializer\br \opt{identifier} \opt{attribute-specifier-seq} \terminal{:} constant-expression \opt{brace-or-equal-initializer} \end{bnf} \begin{bnf} \nontermdef{virt-specifier-seq}\br - virt-specifier\br - virt-specifier-seq virt-specifier + virt-specifier \opt{virt-specifier-seq} \end{bnf} \begin{bnf} @@ -503,6 +593,42 @@ \terminal{=} \terminal{0} \end{bnf} +\begin{bnf} +\nontermdef{friend-type-declaration}\br + \keyword{friend} friend-type-specifier-list \terminal{;} +\end{bnf} + +\begin{bnf} +\nontermdef{friend-type-specifier-list}\br + friend-type-specifier \opt{\terminal{...}}\br + friend-type-specifier-list \terminal{,} friend-type-specifier \opt{\terminal{...}} +\end{bnf} + +\begin{bnf} +\nontermdef{friend-type-specifier}\br + simple-type-specifier\br + elaborated-type-specifier\br + typename-specifier +\end{bnf} + +\pnum +In the absence of a \grammarterm{virt-specifier-seq}, +the token sequence \tcode{= 0} is treated as a \grammarterm{pure-specifier} +if the type of the \grammarterm{declarator-id}\iref{dcl.meaning.general} +is a function type, and +is otherwise treated as a \grammarterm{brace-or-equal-initializer}. +\begin{note} +If the member declaration acquires a function type through +template instantiation, +the program is ill-formed; see~\ref{temp.spec.general}. +\end{note} + +\pnum +The optional \grammarterm{function-contract-specifier-seq}\iref{dcl.contract.func}) +in a \grammarterm{member-declarator} +shall be present only if +the \grammarterm{declarator} declares a function. + \pnum \indextext{definition!class}% The \grammarterm{member-specification} in a class definition declares the @@ -594,7 +720,8 @@ \item function body\iref{dcl.fct.def.general}, \item default argument\iref{dcl.fct.default}, \item default template argument\iref{temp.param}, -\item \grammarterm{noexcept-specifier}\iref{except.spec}, or +\item \grammarterm{noexcept-specifier}\iref{except.spec}, +\item \grammarterm{function-contract-specifier}\iref{dcl.contract.func}, or \item default member initializer \end{itemize} within the \grammarterm{member-specification} of the class or class template. @@ -610,6 +737,11 @@ or if $P$ is in a complete-class context of \tcode{C}. Otherwise, \tcode{C} is incomplete at $P$. +\pnum +If a \grammarterm{member-declaration} matches +the syntactic requirements of \grammarterm{friend-type-declaration}, +it is a \grammarterm{friend-type-declaration}. + \pnum In a \grammarterm{member-declarator}, an \tcode{=} immediately following the \grammarterm{declarator} @@ -765,7 +897,7 @@ \item every member function of class \tcode{T}; \begin{note} This restriction does not apply to constructors, which do not have -names\iref{class.ctor} +names\iref{class.ctor}. \end{note}% \item every member of class \tcode{T} that is itself a type; @@ -796,9 +928,10 @@ \item corresponding entities have the same alignment requirements\iref{basic.align}, \item -either both entities are declared with -the \tcode{no_unique_address} attribute\iref{dcl.attr.nouniqueaddr} -or neither is, and +if a \grammarterm{has-attribute-expression}\iref{cpp.cond} +is not \tcode{0} for the \tcode{no_unique_address} attribute, +then neither entity is declared with +the \tcode{no_unique_address} attribute\iref{dcl.attr.nouniqueaddr}, and \item either both entities are bit-fields with the same width or neither is a bit-field. @@ -910,8 +1043,8 @@ A member function can be declared (but not defined) using a typedef for a function type. The resulting member function has exactly the same type as it would have if the function declarator were provided explicitly, -see~\ref{dcl.fct}. For example, - +see~\ref{dcl.fct} and \ref{temp.arg}. +\begin{example} \begin{codeblock} typedef void fv(); typedef void fvc() const; @@ -924,8 +1057,7 @@ fv S::* pmfv2 = &S::memfunc2; fvc S::* pmfv3 = &S::memfunc3; \end{codeblock} - -Also see~\ref{temp.arg}. +\end{example} \end{note} \rSec2[class.mfct.non.static]{Non-static member functions}% @@ -942,66 +1074,6 @@ its class or a class derived from its class, or a member thereof, as described below. -\pnum -When an \grammarterm{id-expression}\iref{expr.prim.id} that is -neither part of a class member access syntax\iref{expr.ref} -nor the unparenthesized operand of -the unary \tcode{\&} operator\iref{expr.unary.op} is used -where the current class is \tcode{X}\iref{expr.prim.this}, -if name -lookup\iref{basic.lookup} resolves the name in the -\grammarterm{id-expression} to a non-static non-type member of some class -\tcode{C}, -and if either the \grammarterm{id-expression} is potentially evaluated or -\tcode{C} is \tcode{X} or a base class of \tcode{X}, -the \grammarterm{id-expression} is transformed into a class -member access expression\iref{expr.ref} using -\tcode{(*this)} as the \grammarterm{postfix-expression} -to the left of the \tcode{.} operator. -\begin{note} -If \tcode{C} is not \tcode{X} or a base class of \tcode{X}, the class -member access expression is ill-formed. -\end{note} -This transformation does not apply in the -template definition context\iref{temp.dep.type}. -\begin{example} -\begin{codeblock} -struct tnode { - char tword[20]; - int count; - tnode* left; - tnode* right; - void set(const char*, tnode* l, tnode* r); -}; - -void tnode::set(const char* w, tnode* l, tnode* r) { - count = strlen(w)+1; - if (sizeof(tword)<=count) - perror("tnode string too long"); - strcpy(tword,w); - left = l; - right = r; -} - -void f(tnode n1, tnode n2) { - n1.set("abc",&n2,0); - n2.set("def",0,0); -} -\end{codeblock} - -In the body of the member function \tcode{tnode::set}, the member names -\tcode{tword}, \tcode{count}, \tcode{left}, and \tcode{right} refer to -members of the object for which the function is called. Thus, in the -call \tcode{n1.set("abc",\&n2,0)}, \tcode{tword} refers to -\tcode{n1.tword}, and in the call \tcode{n2.set("def",0,0)}, it refers -to \tcode{n2.tword}. The functions \tcode{strlen}, \tcode{perror}, and -\tcode{strcpy} are not members of the class \tcode{tnode} and should be -declared elsewhere. -\begin{footnote} -See, for example, \libheaderref{cstring}. -\end{footnote} -\end{example} - \pnum \indextext{member function!const}% \indextext{member function!volatile}% @@ -1011,7 +1083,7 @@ \grammarterm{cv-qualifier}{s}, which affect the type of the \keyword{this} pointer\iref{expr.prim.this}, and/or a \grammarterm{ref-qualifier}\iref{dcl.fct}; -both affect overload resolution\iref{over.match.funcs} +both affect overload resolution\iref{over.match.funcs}. \end{note} \pnum @@ -1080,7 +1152,7 @@ \end{example} \pnum -Two special member functions are of the same kind if: +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 @@ -1095,7 +1167,9 @@ \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}. +\item no special member function of the same kind +whose associated constraints, if any, are satisfied +is more constrained\iref{temp.constr.order}. \end{itemize} \pnum @@ -1236,7 +1310,7 @@ has a default argument (including the case of a constructor with no parameters). \indextext{implicitly-declared default constructor}% -If there is no user-declared constructor for class +If there is no user-declared constructor or constructor template for class \tcode{X}, a non-explicit constructor having no parameters is implicitly declared as defaulted\iref{dcl.fct.def}. @@ -1244,56 +1318,50 @@ inline public member of its class. \pnum -A defaulted default constructor for class \tcode{X} is defined as deleted if: +A defaulted default constructor for class \tcode{X} is defined as deleted if \begin{itemize} \item any non-static data member with no default member initializer\iref{class.mem} is of reference type, -\item any non-variant non-static data member of const-qualified type -(or possibly multi-dimensional array thereof) +\item \tcode{X} is a non-union class and +any non-variant non-static data member of const-qualified type +(or possibly multidimensional array thereof) with no \grammarterm{brace-or-equal-initializer} is not const-default-constructible\iref{dcl.init}, -\item \tcode{X} is a union and all of its variant members are of const-qualified -type (or possibly multi-dimensional array thereof), - -\item \tcode{X} is a non-union class and all members of any anonymous union member are -of const-qualified type (or possibly multi-dimensional array thereof), - -\item any potentially constructed subobject, except for a non-static data member -with a \grammarterm{brace-or-equal-initializer} -or a variant member of a union where another non-static data member -has a \grammarterm{brace-or-equal-initializer}, -has class type \tcode{M} (or possibly multi-dimensional array thereof) +\item any non-variant potentially constructed subobject, except for a non-static data member +with a \grammarterm{brace-or-equal-initializer}, +has class type \tcode{M} (or possibly multidimensional array thereof) and overload resolution\iref{over.match} as applied to find \tcode{M}'s corresponding constructor -either does not result in a usable candidate\iref{over.match.general} -or, in the case of a variant member, selects a non-trivial function, or +does not result in a usable candidate\iref{over.match.general}, or -\item any potentially constructed subobject has -class type \tcode{M} (or possibly multi-dimensional array thereof) and +\item any potentially constructed subobject $S$ has +class type \tcode{M} (or possibly multidimensional array thereof), \tcode{M} has a destructor that is deleted or inaccessible from the defaulted default -constructor. +constructor, and +either $S$ is non-variant or $S$ has a default member initializer. \end{itemize} \pnum -A default constructor is +A default constructor for a class \tcode{X} is \defnx{trivial}{constructor!default!trivial} -if it is not user-provided and if: +if it is not user-provided and if \begin{itemize} \item -its class has no virtual functions\iref{class.virtual} and no virtual base +\tcode{X} has no virtual functions\iref{class.virtual} and no virtual base classes\iref{class.mi}, and -\item no non-static data member of its class has +\item no non-static data member of \tcode{X} has a default member initializer\iref{class.mem}, and \item -all the direct base classes of its class have trivial default constructors, and +all the direct base classes of \tcode{X} have trivial default constructors, and \item -for all the non-static data members of its class that are of class +either \tcode{X} is a union or +for all the non-variant non-static data members of \tcode{X} that are of class type (or array thereof), each such class has a trivial default constructor. \end{itemize} @@ -1301,7 +1369,18 @@ \defnx{non-trivial}{constructor!default!non-trivial}. \pnum -An implicitly-defined\iref{dcl.fct.def.default} default constructor performs the set of +If a default constructor of a union-like class \tcode{X} is trivial, +then for each union \tcode{U} +that is either \tcode{X} or an anonymous union member of \tcode{X}, +if the first variant member, if any, of \tcode{U} +has implicit-lifetime type\iref{basic.types.general}, +the default constructor of \tcode{X} begins the lifetime of that member +if it is not the active member of its union. +\begin{note} +It is already the active member if \tcode{U} was value-initialized. +\end{note} +Otherwise, +an implicitly-defined\iref{dcl.fct.def.default} default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no \grammarterm{ctor-initializer}\iref{class.base.init} and an empty @@ -1327,7 +1406,7 @@ \indextext{constructor!implicitly invoked}% A default constructor is implicitly invoked to initialize a class object when no initializer is specified\iref{dcl.init.general}. -Such a default constructor is required to be accessible\iref{class.access}. +Such a default constructor needs to be accessible\iref{class.access}. \end{note} \pnum @@ -1538,14 +1617,14 @@ \tcode{X} is defined as deleted\iref{dcl.fct.def.delete} if \tcode{X} has: \begin{itemize} \item a potentially constructed subobject of type - \tcode{M} (or possibly multi-dimensional array thereof) for which + \tcode{M} (or possibly multidimensional array thereof) for which overload resolution\iref{over.match}, as applied to find \tcode{M}'s corresponding constructor, either does not result in a usable candidate\iref{over.match.general} or, in the case of a variant member, selects a non-trivial function, \item any potentially constructed subobject of - class type \tcode{M} (or possibly multi-dimensional array thereof) + class type \tcode{M} (or possibly multidimensional array thereof) where \tcode{M} has a destructor that is deleted or inaccessible from the defaulted constructor, or, @@ -1567,7 +1646,7 @@ \tcode{X} is trivial -if it is not user-provided and if: +if it is not user-provided and if \begin{itemize} \item class @@ -1614,7 +1693,7 @@ \tcode{X} performs a memberwise copy/move of its bases and members. \begin{note} -Default member initializers of non-static data members are ignored. See also the example in~\ref{class.base.init}. +Default member initializers of non-static data members are ignored. \end{note} The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see~\ref{class.base.init}). @@ -1808,12 +1887,12 @@ class \tcode{X} is defined as deleted if \tcode{X} has: \begin{itemize} \item a non-static data member of \keyword{const} non-class - type (or possibly multi-dimensional array thereof), or + type (or possibly multidimensional array thereof), or \item a non-static data member of reference type, or \item a direct non-static data member of class type \tcode{M} - (or possibly multi-dimensional array thereof) or + (or possibly multidimensional array thereof) or a direct base class \tcode{M} that cannot be copied/moved because overload resolution \iref{over.match}, as applied to find \tcode{M}'s corresponding @@ -1833,7 +1912,7 @@ Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden -by the corresponding assignment operator of a derived class\iref{over.ass}. +by the corresponding assignment operator of a derived class\iref{over.assign}. \begin{note} A \grammarterm{using-declaration} in a derived class \tcode{C} that names an assignment operator from a base class @@ -1851,7 +1930,7 @@ \tcode{X} is trivial -if it is not user-provided and if: +if it is not user-provided and if \begin{itemize} \item class @@ -1983,9 +2062,8 @@ shall be \keyword{friend}, \keyword{inline}, -\keyword{virtual}, -\keyword{constexpr}, or -\keyword{consteval}. +\keyword{virtual}, or +\keyword{constexpr}. \pnum \indextext{generated destructor|see{destructor, default}}% @@ -2050,27 +2128,42 @@ \pnum A defaulted destructor for a class - \tcode{X} is defined as deleted if: + \tcode{X} is defined as deleted if \begin{itemize} -\item any potentially constructed subobject has class type - \tcode{M} (or possibly multi-dimensional array thereof) and +\item \tcode{X} is a non-union class and + any non-variant potentially constructed subobject has class type + \tcode{M} (or possibly multidimensional array thereof) where \tcode{M} has a destructor that is deleted or - is inaccessible from the defaulted destructor or, - in the case of a variant member, is non-trivial, + is inaccessible from the defaulted destructor, -\item or, for a virtual destructor, lookup of the non-array deallocation +\item + \tcode{X} is a union and + \begin{itemize} + \item + overload resolution to select a constructor to + default-initialize an object of type \tcode{X} either fails or + selects a constructor that is either deleted or not trivial, or + \item + \tcode{X} has a variant member \tcode{V} of + class type \tcode{M} (or possibly multi-dimensional array thereof) + where \tcode{V} has a default member initializer and + \tcode{M} has a destructor that is non-trivial, or, + \end{itemize} + +\item for a virtual destructor, lookup of the non-array deallocation function results in an ambiguity or in a function that is deleted or inaccessible from the defaulted destructor. \end{itemize} \pnum -A destructor is trivial if it is not user-provided and if: +A destructor for a class \tcode{X} is trivial if it is not user-provided and if \begin{itemize} \item the destructor is not virtual, -\item all of the direct base classes of its class have trivial destructors, and +\item all of the direct base classes of \tcode{X} have trivial destructors, and -\item for all of the non-static data members of its class that are of class +\item either \tcode{X} is a union or +for all of the non-variant non-static data members of \tcode{X} that are of class type (or array thereof), each such class has a trivial destructor. \end{itemize} @@ -2114,7 +2207,8 @@ \tcode{X} calls the destructors for \tcode{X}'s -direct non-variant non-static data members, the destructors for +direct non-variant non-static data members other than anonymous unions, +the destructors for \tcode{X}'s non-virtual direct base classes and, if \tcode{X} @@ -2188,7 +2282,7 @@ In an explicit destructor call, the destructor is specified by a \tcode{\~{}} followed by a -\grammarterm{type-name} or \grammarterm{decltype-specifier} +\grammarterm{type-name} or \grammarterm{computed-type-specifier} that denotes the destructor's class type. The invocation of a destructor is subject to the usual rules for member functions\iref{class.mfct}; @@ -2241,7 +2335,7 @@ Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities. -For example, +\begin{example} \begin{codeblock} void* operator new(std::size_t, void* p) { return p; } struct X { @@ -2257,6 +2351,7 @@ p->X::~X(); // cleanup } \end{codeblock} +\end{example} \end{note} \pnum @@ -2312,8 +2407,7 @@ \pnum \begin{note} -See~\ref{over.match} for a discussion of the use of conversions in function calls -as well as examples below. +See~\ref{over.match} for a discussion of the use of conversions in function calls. \end{note} \pnum @@ -2344,8 +2438,6 @@ specifies a conversion from the types of its parameters (if any) to the type of its class. -Such a constructor is called a -\defnadj{converting}{constructor}. \begin{example} \indextext{Jessie}% \begin{codeblock} @@ -2396,14 +2488,6 @@ \end{example} \end{note} -\pnum -A non-explicit copy/move constructor\iref{class.copy.ctor} is -a converting constructor. -\begin{note} -An implicitly-declared copy/move constructor is not an explicit constructor; -it can be called for implicit type conversions. -\end{note} - \rSec3[class.conv.fct]{Conversion functions}% \indextext{function!conversion}% \indextext{fundamental type conversion|see{conversion, user-defined}}% @@ -2432,10 +2516,9 @@ its \grammarterm{declarator} shall be a function declarator\iref{dcl.fct} of the form \begin{ncsimplebnf} -ptr-declarator \terminal{(} parameter-declaration-clause \terminal{)} \opt{cv-qualifier-seq}\br -\bnfindent \opt{ref-qualifier} \opt{noexcept-specifier} \opt{attribute-specifier-seq} +noptr-declarator parameters-and-qualifiers \end{ncsimplebnf} -where the \grammarterm{ptr-declarator} consists solely of +where the \grammarterm{noptr-declarator} consists solely of an \grammarterm{id-expression}, an optional \grammarterm{attribute-specifier-seq}, and optional surrounding parentheses, and @@ -2454,6 +2537,7 @@ \pnum A conversion function shall have no non-object parameters and shall be a non-static member function of a class or class template \tcode{X}; +its declared return type is the \grammarterm{conversion-type-id} and it specifies a conversion from \tcode{X} to the type specified by the \grammarterm{conversion-type-id}, interpreted as a \grammarterm{type-id}\iref{dcl.name}. @@ -2461,13 +2545,6 @@ of a conversion function (if any) shall not be a \grammarterm{defining-type-specifier}. -\pnum -\indextext{conversion!type of}% -The type of the conversion function is -``\opt{\tcode{noexcept}} function taking no parameter -\opt{\grammarterm{cv-qualifier-seq}} \opt{\grammarterm{ref-qualifier}} -returning \grammarterm{conversion-type-id}''. - \pnum \begin{note} A conversion function is never invoked for @@ -2894,7 +2971,7 @@ refers to an object of class type with a virtual destructor, because the deallocation function is chosen by the destructor of the dynamic type of the object, the effect is the same in that case. -For example, +\begin{example} \begin{codeblock} struct B { virtual ~B(); @@ -2930,6 +3007,7 @@ and its storage is deallocated by \tcode{E::operator delete()}, due to the virtual destructor. +\end{example} \end{note} \begin{note} Virtual destructors have no effect on the deallocation function actually @@ -2938,7 +3016,7 @@ of a \grammarterm{delete-expression} refers to an array of objects of class type. -For example, +\begin{example} \begin{codeblock} struct B { virtual ~B(); @@ -2956,6 +3034,7 @@ delete[] bp; // undefined behavior } \end{codeblock} +\end{example} \end{note} \pnum @@ -3071,8 +3150,7 @@ structs that share a common initial sequence\iref{class.mem}, and if a non-static data member of an object of this standard-layout union type is active and is one of the standard-layout structs, -it is permitted to inspect the common initial sequence -of any of the standard-layout struct members; +the common initial sequence of any of the standard-layout struct members can be inspected; see~\ref{class.mem}. \end{note} @@ -3097,14 +3175,14 @@ base classes. A union shall not be used as a base class. \indextext{restriction!\idxcode{union}}% If a union contains a non-static data member of -reference type the program is ill-formed. -\begin{note} -Absent default member initializers\iref{class.mem}, -if any non-static data member of a union has a non-trivial -default constructor\iref{class.default.ctor}, -copy constructor, move constructor\iref{class.copy.ctor}, -copy assignment operator, move assignment operator\iref{class.copy.assign}, -or destructor\iref{class.dtor}, the corresponding member function +reference type, the program is ill-formed. +\begin{note} +If any non-static data member of a union has a non-trivial +copy constructor, +move constructor\iref{class.copy.ctor}, +copy assignment operator, or +move assignment operator\iref{class.copy.assign}, +the corresponding member function of the union must be user-provided or it will be implicitly deleted\iref{dcl.fct.def.delete} for the union. \begin{example} @@ -3117,11 +3195,11 @@ }; \end{codeblock} Since \tcode{std::string}\iref{string.classes} declares non-trivial versions of all of the special -member functions, \tcode{U} will have an implicitly deleted default constructor, -copy/move constructor, -copy/move assignment operator, and destructor. -To use \tcode{U}, some or all of these member functions -must be user-provided. +member functions, \tcode{U} will have an implicitly deleted +copy/move constructor and copy/move assignment operator. +The default constructor and destructor of \tcode{U} are both trivial +even though \tcode{std::string} has +a non-trivial default constructor and a non-trivial destructor. \end{example} \end{note} @@ -3153,9 +3231,12 @@ Otherwise, $S(\mathtt{E})$ is empty. \end{itemize} In an assignment expression of the form \tcode{E1 = E2} -that uses either the built-in assignment operator\iref{expr.ass} +that uses either the built-in assignment operator\iref{expr.assign} or a trivial assignment operator\iref{class.copy.assign}, -for each element \tcode{X} of $S($\tcode{E1}$)$, +for each element \tcode{X} of $S($\tcode{E1}$)$ and +each anonymous union member \tcode{X}\iref{class.union.anon} that +is a member of a union and +has such an element as an immediate subobject (recursively), if modification of \tcode{X} would have undefined behavior under~\ref{basic.life}, an object of the type of \tcode{X} is implicitly created in the nominated storage; @@ -3353,13 +3434,13 @@ \pnum \indextext{nested class!local class}% -If class \tcode{X} is a local class, a nested class \tcode{Y} may be -declared in class \tcode{X} and later defined in the definition of class -\tcode{X} or be later defined in the same scope as the definition of -class \tcode{X}. \indextext{restriction!local class}% A class nested within a local class is a local class. +A member of a local class \tcode{X} shall be +declared only in the definition of \tcode{X} or, +if the member is a nested class, +in the nearest enclosing block scope of \tcode{X}. \pnum \indextext{restriction!static member local class}% @@ -3406,7 +3487,7 @@ \nontermdef{class-or-decltype}\br \opt{nested-name-specifier} type-name\br nested-name-specifier \keyword{template} simple-template-id\br - decltype-specifier + computed-type-specifier \end{bnf} \indextext{specifier access|see{access specifier}}% @@ -3730,13 +3811,13 @@ determining overriding. \end{footnote} $F$. -For convenience we say that any virtual function overrides itself. +For convenience, we say that any virtual function overrides itself. \indextext{overrider!final}% A virtual member function $V$ of a class object $S$ is a \defn{final overrider} unless the most derived class\iref{intro.object} of which $S$ is a base class subobject (if any) has another member function that overrides $V$. In a derived class, if a virtual member function of a base class subobject -has more than one final overrider the program is ill-formed. +has more than one final overrider, the program is ill-formed. \begin{example} \begin{codeblock} struct A { @@ -4268,8 +4349,7 @@ Because access control applies to the declarations named, if access control is applied to a \grammarterm{typedef-name}, only the accessibility of the typedef or alias declaration itself is considered. The accessibility of the entity referred to by the \grammarterm{typedef-name} is not considered. -For example, - +\begin{example} \begin{codeblock} class A { class B { }; @@ -4282,6 +4362,7 @@ A::B y; // access error, \tcode{A::B} is private } \end{codeblock} +\end{example} \end{note} \pnum @@ -4311,8 +4392,8 @@ \begin{codeblock} class A { typedef int I; // private member - I f(); - friend I g(I); + I f() pre(A::x > 0); + friend I g(I) post(A::x <= 0); static I x; template struct Q; template friend struct R; @@ -4320,8 +4401,8 @@ struct B { }; }; -A::I A::f() { return 0; } -A::I g(A::I p = A::x); +A::I A::f() pre(A::x > 0) { return 0; } +A::I g(A::I p = A::x) post(A::x <= 0); A::I g(A::I p) { return 0; } A::I A::x = 0; template struct A::Q { }; @@ -4546,8 +4627,7 @@ a conversion from a pointer to a derived class to a pointer to an inaccessible base class can be ill-formed if an implicit conversion is used, but well-formed if an explicit cast is used. -For example, - +\begin{example} \begin{codeblock} class B { public: @@ -4572,6 +4652,7 @@ bp2->mi = 3; // OK, access through a pointer to \tcode{B}. } \end{codeblock} +\end{example} \end{note} \pnum @@ -4836,27 +4917,22 @@ \pnum A friend declaration that does not declare a function -shall have one of the following forms: - -\begin{ncsimplebnf} -\keyword{friend} elaborated-type-specifier \terminal{;}\br -\keyword{friend} simple-type-specifier \terminal{;}\br -\keyword{friend} typename-specifier \terminal{;} -\end{ncsimplebnf} +shall be a \grammarterm{friend-type-declaration}. \begin{note} A friend declaration can be the \grammarterm{declaration} in a \grammarterm{template-declaration}\iref{temp.pre,temp.friend}. \end{note} -If the -type specifier in a \keyword{friend} declaration designates a (possibly +If a \grammarterm{friend-type-specifier} in a friend declaration +designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, the -friend declaration is ignored. +\grammarterm{friend-type-specifier} is ignored. \begin{example} \begin{codeblock} class C; typedef C Ct; +class E; class X1 { friend C; // OK, \tcode{class C} is a friend @@ -4868,21 +4944,25 @@ friend class D; // OK, elaborated-type-specifier declares new class }; -template class R { - friend T; +template class R { + friend Ts...; +}; + +template +class R, R> { + friend Ts::Nested..., Us...; }; R rc; // \tcode{class C} is a friend of \tcode{R} -R Ri; // OK, \tcode{"friend int;"} is ignored +R rce; // classes \tcode{C} and \tcode{E} are friends of \tcode{R} +R Ri; // OK, ``\tcode{friend int;}'' is ignored + +struct E { struct Nested; }; + +R, R> rr; // \tcode{E::Nested} and \tcode{C} are friends of \tcode{R, R>} \end{codeblock} \end{example} -\pnum -\indextext{friend function!linkage of}% -A function first declared in a friend declaration -has the linkage of the namespace of which it is a member\iref{basic.link}. -Otherwise, the function retains its previous linkage\iref{dcl.stc}. - \pnum \indextext{declaration!overloaded name and \tcode{friend}}% \begin{note} @@ -5257,7 +5337,7 @@ \end{example} \begin{note} \indextext{initialization!overloaded assignment and}% -Overloading of the assignment operator\iref{over.ass} +Overloading of the assignment operator\iref{over.assign} has no effect on initialization. \end{note} @@ -5318,7 +5398,7 @@ If \tcode{T} is a class type with no default constructor, -any declaration of an object of type +any initializing declaration of an object of type \tcode{T} (or array thereof) is ill-formed if no \grammarterm{initializer} @@ -5554,7 +5634,7 @@ is neither initialized nor given a value during execution of the \grammarterm{compound-statement} of the body of the constructor, -the member has an indeterminate value. +the member has an indeterminate or erroneous value\iref{basic.indet}. \end{note} \begin{example} \begin{codeblock} @@ -5570,7 +5650,7 @@ C() { } // initializes members as follows: A a; // OK, calls \tcode{A::A()} const B b; // error: \tcode{B} has no default constructor - int i; // OK, \tcode{i} has indeterminate value + int i; // OK, \tcode{i} has indeterminate or erroneous value int j = 5; // OK, \tcode{j} has the value \tcode{5} }; \end{codeblock} @@ -5738,18 +5818,27 @@ \pnum \indextext{initialization!member function call during}% Member functions (including virtual member functions, \ref{class.virtual}) can be -called for an object under construction. -Similarly, an object under construction can be the operand of the +called for an object under construction or destruction. +Similarly, an object under construction or destruction can be the operand of the \tcode{typeid} operator\iref{expr.typeid} or of a \keyword{dynamic_cast}\iref{expr.dynamic.cast}. -However, if these operations are performed in a -\grammarterm{ctor-initializer} +However, if these operations are performed +during evaluation of +\begin{itemize} +\item +a \grammarterm{ctor-initializer} (or in a function called directly or indirectly from a \grammarterm{ctor-initializer}) before all the \grammarterm{mem-initializer}{s} -for base classes have completed, the program has undefined behavior. +for base classes have completed, +\item +a precondition assertion of a constructor, or +\item +a postcondition assertion of a destructor\iref{dcl.contract.func}, +\end{itemize} +the program has undefined behavior. \begin{example} \begin{codeblock} class A { @@ -5818,9 +5907,16 @@ were used to initialize the \tcode{D} object and each base class subobject from which the constructor was inherited, except that the \tcode{B} subobject is initialized -by the invocation of the inherited constructor. +by the inherited constructor +if the base class subobject were to be initialized +as part of the \tcode{D} object\iref{class.base.init}. +The invocation of the inherited constructor, +including the evaluation of any arguments, +is omitted if the \tcode{B} subobject is not to be initialized +as part of the \tcode{D} object. The complete initialization is considered to be a single function call; -in particular, the initialization of the inherited constructor's parameters +in particular, unless omitted, +the initialization of the inherited constructor's parameters is sequenced before the initialization of any part of the \tcode{D} object. \begin{example} \begin{codeblock} @@ -5870,6 +5966,23 @@ whenever an object of class \tcode{Log} is destroyed. \end{example} +\begin{example} +\begin{codeblock} +struct V { V() = default; V(int); }; +struct Q { Q(); }; +struct A : virtual V, Q { + using V::V; + A() = delete; +}; +int bar() { return 42; } +struct B : A { + B() : A(bar()) {} // OK +}; +struct C : B {}; +void foo() { C c; } // \tcode{bar} is not invoked, because the \tcode{V} subobject is not initialized as part of \tcode{B} +\end{codeblock} +\end{example} + \pnum If the constructor was inherited from multiple base class subobjects of type \tcode{B}, the program is ill-formed. @@ -5941,7 +6054,7 @@ B bobj; // definition of \tcode{bobj} extern X xobj; -int* p3 = &xobj.i; // OK, \tcode{X} is a trivial class +int* p3 = &xobj.i; // OK, all constructors of \tcode{X} are trivial X xobj; \end{codeblock} For another example, @@ -5959,11 +6072,12 @@ \pnum During the construction of an object, -if the value of the object or any of its subobjects is -accessed through a glvalue that is not obtained, directly or indirectly, from +if the value of any of its subobjects +or any element of its object representation +is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor's \keyword{this} -pointer, the value of the object or subobject thus obtained is unspecified. +pointer, the value thus obtained is unspecified. \begin{example} \begin{codeblock} struct C; @@ -6048,6 +6162,9 @@ or from a destructor, including during the construction or destruction of the class's non-static data members, +or during the evaluation of +a postcondition assertion of a constructor or +a precondition assertion of a destructor\iref{dcl.contract.func}, and the object to which the call applies is the object (call it \tcode{x}) under construction or destruction, the function called is the @@ -6177,25 +6294,26 @@ \indextext{constructor!copy!elision}% \indextext{constructor!move!elision}% When certain criteria are met, an implementation is -allowed to omit the copy/move construction of a class object, -even if the constructor selected for the copy/move operation and/or the +allowed to omit the creation of a class object from +a source object of the same type (ignoring cv-qualification), +even if the selected constructor and/or the destructor for the object have \indextext{side effects}% side effects. In such cases, the implementation treats the source and target of the -omitted copy/move operation as simply two different ways of +omitted initialization as simply two different ways of referring to the same object. If the first parameter of the selected constructor is an rvalue reference to the object's type, the destruction of that object occurs when the target would have been destroyed; otherwise, the destruction occurs at the later of the times when the two objects would have been destroyed without the optimization. -\begin{footnote} +\begin{note} Because only one object is destroyed instead of two, -and one copy/move constructor -is not executed, there is still one object destroyed for each one constructed. -\end{footnote} -This elision of copy/move operations, called +and the creation of one object is omitted, +there is still one object destroyed for each one constructed. +\end{note} +This elision of object creation, called \indexdefn{copy elision|see{constructor, copy, elision}}% \indexdefn{elision!copy|see{constructor, copy, elision}}% \indexdefn{constructor!copy!elision}\indexdefn{constructor!move!elision}\term{copy elision}, @@ -6203,34 +6321,35 @@ following circumstances (which may be combined to eliminate multiple copies): \begin{itemize} -\item in a \tcode{return} statement in a function with a class return type, +\item in a \tcode{return} statement\iref{stmt.return} in +a function with a class return type, when the \grammarterm{expression} is the name of a non-volatile -object with automatic storage duration (other than a function parameter or a variable +object $o$ with automatic storage duration (other than a function parameter or a variable introduced by the \grammarterm{exception-declaration} of a -\grammarterm{handler}\iref{except.handle}) -with the same type (ignoring cv-qualification) as -the function return type, the copy/move operation can be -omitted by constructing the object directly -into the function call's return object +\grammarterm{handler}\iref{except.handle}), +the copy-initialization of the result object can be +omitted by constructing $o$ directly +into the function call's result object; \item in a \grammarterm{throw-expression}\iref{expr.throw}, when the operand -is the name of a non-volatile object with automatic storage duration -(other than a function or catch-clause parameter) +is the name of a non-volatile object $o$ with automatic storage duration +(other than a function parameter or +a variable introduced by +the \grammarterm{exception-declaration} of a \grammarterm{handler}) that belongs to a scope that does not contain the innermost enclosing \grammarterm{compound-statement} associated with a \grammarterm{try-block} (if there is one), -the copy/move operation can be omitted by -constructing the object directly into the exception object +the copy-initialization of the exception object can be omitted by +constructing $o$ directly into the exception object; \item in a coroutine\iref{dcl.fct.def.coroutine}, a copy of a coroutine parameter can be omitted and references to that copy replaced with references to the corresponding parameter if the meaning of the program will be unchanged except for -the execution of a constructor and destructor for the parameter copy object +the execution of a constructor and destructor for the parameter copy object; \item when the \grammarterm{exception-declaration} of a -\grammarterm{handler}\iref{except.handle} declares an object of the same -type (except for cv-qualification) as the exception -object\iref{except.throw}, the copy operation can be omitted by treating +\grammarterm{handler}\iref{except.handle} declares an object $o$, +the copy-initialization of $o$ can be omitted by treating the \grammarterm{exception-declaration} as an alias for the exception object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by the @@ -6378,12 +6497,15 @@ \pnum A defaulted comparison operator function\iref{over.binary} -for some class \tcode{C} shall be a non-template function -that is +that \begin{itemize} \item -a non-static member or friend of \tcode{C} and +is a non-static member or friend of some class \tcode{C}, + +\item +is defined as defaulted in \tcode{C} or in +a context where \tcode{C} is complete, and \item either has @@ -6392,13 +6514,28 @@ where the implicit object parameter (if any) is considered to be the first parameter. \end{itemize} -Name lookups in the implicit definition\iref{dcl.fct.def.default} +Such a comparison operator function is termed +\indextext{operator!defaulted comparison operator function}% +a defaulted comparison operator function for class \tcode{C}. +Name lookups and access checks in +the implicit definition\iref{dcl.fct.def.default} of a comparison operator function are performed from a context equivalent to its \grammarterm{function-body}. A definition of a comparison operator as defaulted that appears in a class shall be the first declaration of that function. +\begin{example} +\begin{codeblock} +struct S; +bool operator==(S, S) = default; // error: \tcode{S} is not complete +struct S { + friend bool operator==(S, const S&) = default; // error: parameters of different types +}; +enum E { }; +bool operator==(E, E) = default; // error: not a member or friend of a class +\end{codeblock} +\end{example} \pnum A defaulted \tcode{<=>} or \tcode{==} operator function for class \tcode{C} @@ -6511,8 +6648,8 @@ until the first index $i$ where $\tcode{x}_i\tcode{ == }\tcode{y}_i$ yields a result value which, when contextually converted to \tcode{bool}, yields \tcode{false}. -The return value is \tcode{true} if such an index exists -and \tcode{false} otherwise. +The return value is \tcode{false} if such an index exists +and \tcode{true} otherwise. \pnum \begin{example} @@ -6541,7 +6678,8 @@ \tcode{static_cast(a <=> b)}. \item -Otherwise, if overload resolution for \tcode{a <=> b} is performed and +Otherwise, if \tcode{a <=> b} is usable or +overload resolution for \tcode{a <=> b} is performed and finds at least one viable candidate, the synthesized three-way comparison is not defined. @@ -6666,18 +6804,29 @@ is defined as deleted if \begin{itemize} \item -overload resolution\iref{over.match}, +a first overload resolution\iref{over.match}, as applied to \tcode{x @ y}, +\begin{itemize} +\item does not result in a usable candidate, or - \item -the candidate selected by overload resolution -is not a rewritten candidate. +the selected candidate is not a rewritten candidate, or \end{itemize} +\item +a second overload resolution for +the expression resulting from the interpretation of \tcode{x @ y} +using the selected rewritten candidate\iref{over.match.oper} +does not result in a usable candidate +(for example, that expression might be \tcode{(x <=> y) @ 0}), or + +\item +\tcode{x @ y} cannot be implicitly converted to \tcode{bool}. +\end{itemize} +In any of the two overload resolutions above, +the defaulted operator function is not considered as +a candidate for the \tcode{@} operator. Otherwise, the operator function yields \tcode{x @ y}. -The defaulted operator function is not considered as a candidate -in the overload resolution for the \tcode{@} operator. \pnum \begin{example} diff --git a/source/compatibility.tex b/source/compatibility.tex index 70716c9d45..2e4d0d5bb6 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -8,11 +8,105 @@ \pnum \indextext{summary!compatibility with ISO \CppXXIII{}}% Subclause \ref{diff.cpp23} lists the differences between \Cpp{} and -ISO \CppXXIII{} (ISO/IEC 14882:2023, \doccite{Programming Languages --- \Cpp{}}), +ISO \CppXXIII{}, by the chapters of this document. +\rSec2[diff.cpp23.lex]{\ref{lex}: Lexical conventions} + +\diffref{lex.key} +\change +New keywords. +\rationale +Required for new features. +\begin{itemize} +\item +The \keyword{contract_assert} keyword +is added to introduce a contract assertion +through an \grammarterm{assertion-statement}\iref{stmt.contract.assert}. +\end{itemize} +\effect +Valid \CppXXIII{} code using \keyword{contract_assert} as an identifier +is not valid in this revision of \Cpp{}. + \rSec2[diff.cpp23.expr]{\ref{expr}: expressions} +\diffref{expr.arith.conv} +\change +Operations mixing a value of an enumeration type and a value of a different +enumeration type or of a floating-point type are no longer valid. +\rationale +Reinforcing type safety. +\effect +A valid \CppXXIII{} program that performs operations mixing a value of an +enumeration type and a value of a different enumeration type or of a +floating-point type is ill-formed. +\begin{example} +\begin{codeblock} +enum E1 { e }; +enum E2 { f }; +bool b = e <= 3.7; // ill-formed; previously well-formed +int k = f - e; // ill-formed; previously well-formed +auto x = true ? e : f; // ill-formed; previously well-formed +\end{codeblock} +\end{example} + +\diffref{expr.rel,expr.eq} +\change +Comparing two objects of array type is no longer valid. +\rationale +The old behavior was confusing since it compared not the contents of the two +arrays, but their addresses. +\effect +A valid \CppXXIII{} program directly comparing two array objects is rejected as +ill-formed in this document. +\begin{example} +\begin{codeblock} +int arr1[5]; +int arr2[5]; +bool same = arr1 == arr2; // ill-formed; previously well-formed +bool idem = arr1 == +arr2; // compare addresses +bool less = arr1 < +arr2; // compare addresses, unspecified result +\end{codeblock} +\end{example} + +\diffref{expr.delete} +\change +Calling \tcode{delete} on a pointer to an incomplete class is ill-formed. +\rationale +Reduce undefined behavior. +\effect +A valid \CppXXIII{} program that calls \tcode{delete} on an incomplete +class type is ill-formed. +\begin{example} +\begin{codeblock} +struct S; + +void f(S *p) { + delete p; // ill-formed; previously well-formed +} + +struct S {}; +\end{codeblock} +\end{example} + +\rSec2[diff.cpp23.dcl.dcl]{\ref{dcl}: declarations} + +\diffref{dcl.decl.general} +\change +Introduction of \tcode{trivially_relocatable_if_eligible} and +\tcode{replaceable_if_eligible} as identifiers with special meaning\iref{lex.name}. +\rationale +Support declaration of trivially relocatable and replaceable types\iref{class.prop}. +\effect +Valid \CppXXIII{} code can become ill-formed. +\begin{example} +\begin{codeblock} +struct C {}; +struct C replaceable_if_eligible {}; // was well-formed (new variable \tcode{replaceable_if_eligible}) + // now ill-formed (redefines \tcode{C}) +\end{codeblock} +\end{example} + \diffref{dcl.init.list} \change Pointer comparisons between \tcode{initializer_list} objects' backing arrays @@ -23,13 +117,128 @@ Valid \CppXXIII{} code that relies on the result of pointer comparison between backing arrays may change behavior. -For example: +\begin{example} \begin{codeblock} bool ne(std::initializer_list a, std::initializer_list b) { return a.begin() != b.begin() + 1; } bool b = ne({2,3}, {1,2,3}); // unspecified result; previously \tcode{false} \end{codeblock} +\end{example} + +\diffref{dcl.array} +\change +Previously, \tcode{T...[n]} would declare a pack of function parameters. +\tcode{T...[n]} is now a \grammarterm{pack-index-specifier}. +\rationale +Improve the handling of packs. +\effect +Valid \CppXXIII{} code that declares a pack of parameters +without specifying a \grammarterm{declarator-id} becomes ill-formed. +\begin{example} +\begin{codeblock} +template +void f(T... [1]); +template +void g(T... ptr[1]); +int main() { + f(nullptr, nullptr); // ill-formed, previously \tcode{void f(int [1], double [1])} + g(nullptr, nullptr); // ok +} +\end{codeblock} +\end{example} + +\rSec2[diff.cpp23.temp]{\ref{temp}: templates} + +\diffref{temp.constr} +\change +Some atomic constraints become fold expanded constraints. +\rationale +Permit the subsumption of fold expressions. +\effect +Valid \CppXXIII{} code may become ill-formed. +\begin{example} +\begin{codeblock} +template struct A; +struct S { + static constexpr int compare(const S&) { return 1; } +}; + +template +void f(A *, A *) +requires (T::compare(U{}) && ...); // was well-formed (atomic constraint of type \tcode{bool}), + // now ill-formed (results in an atomic constraint of type \tcode{int}) +void g(A *ap) { + f(ap, ap); +} +\end{codeblock} +\end{example} + +\diffref{temp.deduct.call} +\change +Template argument deduction from overload sets succeeds in more cases. +\rationale +Allow consideration of constraints to disambiguate overload sets +used as parameters in function calls. +\effect +Valid \CppXXIII{} code may become ill-formed. +\begin{example} +\begin{codeblock} +template +void f(T &&, void (*)(T &&)); + +void g(int &); // \#1 +inline namespace A { + void g(short &&); // \#2 +} +inline namespace B { + void g(short &&); // \#3 +} + +void q() { + int x; + f(x, g); // ill-formed; previously well-formed, deducing \tcode{T = int\&} +} +\end{codeblock} +There is no change to the applicable deduction rules for +the individual \tcode{g} candidates: +Type deduction from \#1 does not succeed; +type deductions from \#2 and \#3 both succeed. +\end{example} + +\rSec2[diff.cpp23.library]{\ref{library}: library introduction} + +\diffref{headers} +\change +New headers. +\rationale +New functionality. +\effect +The following \Cpp{} headers are new: +\libheaderrefx{contracts}{support.contract}, +\libheaderref{debugging}, +\libheaderrefx{hazard_pointer}{hazard.pointer.syn}, +\libheaderref{hive}, +\libheaderrefx{inplace_vector}{inplace.vector.syn}, +\libheaderref{linalg}, +\libheaderref{rcu}, +\libheaderref{simd}, +\libheaderref{stdbit.h}, +\libheaderref{stdckdint.h}, and +\libheaderrefx{text_encoding}{text.encoding.syn}. +Valid \CppXXIII{} code that \tcode{\#include}{s} headers with these names may be +invalid in this revision of \Cpp{}. + +\diffref{res.on.macro.definitions} +\change +Additional restrictions on macro names. +\rationale +Avoid hard to diagnose or non-portable constructs. +\effect +Names of special identifiers may not be used as macro names. +Valid \CppXXIII{} code that defines \tcode{replaceable_if_eligible} or +\tcode{trivially_relocatable_if_eligible} as macros is invalid +in this revision of \Cpp{}. \rSec2[diff.cpp23.strings]{\ref{strings}: strings library} @@ -42,12 +251,141 @@ \effect \tcode{to_string} and \tcode{to_wstring} function calls that take floating-point arguments may produce a different output. -For example: +\begin{example} \begin{codeblock} auto s = std::to_string(1e-7); // \tcode{"1e-07"} // previously \tcode{"0.000000"} with \tcode{'.'} possibly // changed according to the global C locale \end{codeblock} +\end{example} + +\rSec2[diff.cpp23.containers]{\ref{containers}: containers library} + +\diffref{span.overview} +\change +\tcode{span} is constructible from \tcode{initializer_list}. +\rationale +Permit passing a braced initializer list to a function taking \tcode{span}. +\effect +Valid \CppXXIII{} code that relies on the lack of this constructor +may refuse to compile, or change behavior in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +void one(pair); // \#1 +void one(span); // \#2 +void t1() { one({1, 2}); } // ambiguous between \#1 and \#2; previously called \#1 + +void two(span); +void t2() { two({{1, 2}}); } // ill-formed; previously well-formed + +void *a[10]; +int x = span{a, 0}.size(); // \tcode{x} is \tcode{2}; previously \tcode{0} +any b[10]; +int y = span{b, b + 10}.size(); // \tcode{y} is \tcode{2}; previously \tcode{10} +\end{codeblock} +\end{example} + +\rSec2[diff.cpp23.depr]{\ref{depr}: compatibility features} + +\nodiffref +\change +Remove the type alias \tcode{allocator::is_always_equal}. +\rationale +Non-empty allocator classes derived from \tcode{allocator} needed to explicitly +define an \tcode{is_always_equal} member type so that \tcode{allocator_traits} +would not use the one from the allocator base class. +\effect +It is simpler to correctly define an allocator class with an allocator base +class. +\begin{example} +\begin{codeblock} +template +struct MyAlloc : allocator { + int tag; +}; + +static_assert(!allocator_traits>::is_always_equal); // Error in \CppXXIII{}, + // OK in \CppXXVI{} +\end{codeblock} +\end{example} + +\nodiffref +\change +Removal of atomic access API for \tcode{shared_ptr} objects. +\rationale +The old behavior was brittle. \tcode{shared_ptr} objects using the old API were +not protected by the type system, and certain interactions with code not using +this API would, in some cases, silently produce undefined behavior. A complete +type-safe replacement is provided in the form of \tcode{atomic>}. +\effect +A valid \CppXXIII{} program that relies on the presence of the removed functions +may fail to compile. + +\nodiffref +\change +Remove the \tcode{basic_string::reserve()} overload with no parameters. +\rationale +The overload of \tcode{reserve} with no parameters is redundant. +The \tcode{shrink_to_fit} member function can be used instead. +\effect +A valid \CppXXIII{} program that calls \tcode{reserve()} +on a \tcode{basic_string} object may fail to compile. +The old functionality can be achieved by calling \tcode{shrink_to_fit()} instead, +or the function call can be safely eliminated with no side effects. + +\nodiffref +\change +Remove header \libnoheader{codecvt} and all its contents. +\rationale +The header has been deprecated for the previous three editions of this document +and no longer implements the current Unicode standard, supporting only the +obsolete UCS-2 encoding. +Ongoing support is at implementer's discretion, +exercising freedoms granted by \ref{zombie.names}. +\effect +A valid \CppXXIII{} program \tcode{\#include}-ing the header or importing the +header unit may fail to compile. Code that uses any of the following names by +importing the standard library modules may fail to compile: +\begin{itemize} +\item \tcode{codecvt_mode}, +\item \tcode{codecvt_utf16}, +\item \tcode{codecvt_utf8}, +\item \tcode{codecvt_utf8_utf16}, +\item \tcode{consume_header}, +\item \tcode{generate_header}, and +\item \tcode{little_endian}. +\end{itemize} + +\nodiffref +\change +Remove header \libnoheader{strstream} and all its contents. +\rationale +The header has been deprecated since the original \Cpp{} standard; the +\libheader{spanstream} header provides an updated, safer facility. +Ongoing support is at implementer's discretion, +exercising freedoms granted by \ref{zombie.names}. +\effect +A valid \CppXXIII{} program \tcode{\#include}-ing the header or importing the +header unit may become ill-formed. Code that uses any of the following classes +by importing one of the standard library modules may become ill-formed: +\begin{itemize} +\item \tcode{istrstream} +\item \tcode{ostrstream} +\item \tcode{strstream} +\item \tcode{strstreambuf} +\end{itemize} + +\nodiffref +\change +Remove convenience interfaces \tcode{wstring_convert} and +\tcode{wbuffer_convert}. +\rationale +These features were underspecified with no clear error reporting mechanism and +were deprecated for the last three editions of this document. +Ongoing support is at implementer's discretion, +exercising freedoms granted by \ref{zombie.names}. +\effect +A valid \CppXXIII{} program using these interfaces may become ill-formed. \rSec1[diff.cpp20]{\Cpp{} and ISO \CppXX{}} @@ -56,12 +394,15 @@ \pnum \indextext{summary!compatibility with ISO \CppXX{}}% Subclause \ref{diff.cpp20} lists the differences between \Cpp{} and -ISO \CppXX{} (ISO/IEC 14882:2020, \doccite{Programming Languages --- \Cpp{}}), +ISO \CppXX{}, +in addition to those listed above, by the chapters of this document. \rSec2[diff.cpp20.lex]{\ref{lex}: lexical conventions} \diffref{lex.name} +\indextext{XID_Start}% +\indextext{XID_Continue}% \change Previously valid identifiers containing characters not present in \UAX{44} properties XID_Start or XID_Continue, or @@ -82,10 +423,11 @@ Concatenation of \grammarterm{string-literal}s with different \grammarterm{encoding-prefix}es is now ill-formed. -For example: +\begin{example} \begin{codeblock} auto c = L"a" U"b"; // was conditionally-supported; now ill-formed \end{codeblock} +\end{example} \rSec2[diff.cpp20.expr]{\ref{expr}: expressions} @@ -97,11 +439,12 @@ \effect Valid \CppXX{} code that relies on a returned \grammarterm{id-expression}'s being an lvalue may change behavior or fail to compile. -For example: +\begin{example} \begin{codeblock} decltype(auto) f(int&& x) { return (x); } // returns \tcode{int\&\&}; previously returned \tcode{int\&} int& g(int&& x) { return x; } // ill-formed; previously well-formed \end{codeblock} +\end{example} \diffref{expr.sub} \change @@ -111,13 +454,14 @@ \effect Valid \CppXX{} code that uses a comma expression within a subscript expression may fail to compile. -For example: +\begin{example} \begin{codeblock} arr[1, 2] // was equivalent to \tcode{arr[(1, 2)]}, // now equivalent to \tcode{arr.operator[](1, 2)} or ill-formed \end{codeblock} +\end{example} -\rSec2[diff.cpp20.stmt]{\ref{stmt.stmt}: statements} +\rSec2[diff.cpp20.stmt]{\ref{stmt}: statements} \diffref{stmt.ranged} \change @@ -127,7 +471,7 @@ Improve usability of the range-based \keyword{for} statement. \effect Destructors of some temporary objects are invoked later. -For example: +\begin{example} \begin{codeblock} void f() { std::vector v = { 42, 17, 13 }; @@ -139,8 +483,9 @@ } } \end{codeblock} +\end{example} -\rSec2[diff.cpp20.dcl]{\ref{dcl.dcl}: declarations} +\rSec2[diff.cpp20.dcl]{\ref{dcl}: declarations} \diffref{dcl.init.string} \change @@ -153,7 +498,7 @@ may now be initialized with a UTF-8 string literal. This can affect initialization that includes arrays that are directly initialized within class types, typically aggregates. -For example: +\begin{example} \begin{codeblock} struct A { char8_t s[10]; @@ -169,6 +514,7 @@ f({u8""}); // ambiguous } \end{codeblock} +\end{example} \rSec2[diff.cpp20.temp]{\ref{temp}: templates} @@ -179,7 +525,7 @@ Facilitate generic handling of throwing and non-throwing functions. \effect Valid ISO \CppXX{} code may be ill-formed in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} template struct A { }; template void f(void (*)(A) noexcept(B)); @@ -188,6 +534,7 @@ f(g); // ill-formed; previously well-formed } \end{codeblock} +\end{example} \rSec2[diff.cpp20.library]{\ref{library}: library introduction} @@ -224,7 +571,7 @@ Valid \CppXX{} code relying on subsumption with \tcode{common_reference_with} may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} template requires @\libconcept{equality_comparable_with}@ @@ -238,6 +585,7 @@ return attempted_equals(p, nullptr); // ill-formed; previously well-formed } \end{codeblock} +\end{example} \rSec2[diff.cpp20.memory]{\ref{mem}: memory management library} @@ -268,11 +616,12 @@ contained errors in format strings or relied on previous format string signatures or \tcode{format_args_t} may become ill-formed. -For example: +\begin{example} \begin{codeblock} auto s = std::format("{:d}", "I am not a number"); // ill-formed, // previously threw \tcode{format_error} \end{codeblock} +\end{example} \diffref{format} \change @@ -285,7 +634,7 @@ \effect Valid \CppXX{} code that passes bit-fields to formatting functions may become ill-formed. -For example: +\begin{example} \begin{codeblock} struct tiny { int bit: 1; @@ -294,6 +643,7 @@ auto t = tiny(); std::format("{}", t.bit); // ill-formed, previously returned \tcode{"0"} \end{codeblock} +\end{example} \diffref{format.string.std} \change @@ -306,12 +656,13 @@ \effect Valid \CppXX{} code that passes a boolean or character type as \fmtgrammarterm{arg-id} becomes invalid. -For example: +\begin{example} \begin{codeblock} std::format("{:*^{}}", "", true); // ill-formed, previously returned \tcode{"*"} std::format("{:*^{}}", "", '1'); // ill-formed, previously returned an // implementation-defined number of \tcode{'*'} characters \end{codeblock} +\end{example} \diffref{format.formatter.spec} \change @@ -340,7 +691,7 @@ on an xvalue expression with type \tcode{S} that is a specialization of \tcode{basic_string} may change meaning in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} std::string s1 = "some long string that forces allocation", s2 = s1; std::move(s1).substr(10, 5); @@ -348,6 +699,7 @@ std::string s3(std::move(s2), 10, 5); assert(s1 == s2); // unspecified, previously guaranteed to be \tcode{true} \end{codeblock} +\end{example} \rSec2[diff.cpp20.containers]{\ref{containers}: containers library} @@ -359,7 +711,7 @@ Improve efficiency of erasing elements from associative containers. \effect Valid \CppXX{} code may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct B { auto operator<=>(const B&) const = default; @@ -371,6 +723,7 @@ } }; \end{codeblock} +\end{example} \rSec2[diff.cpp20.thread]{\ref{thread}: concurrency support library} @@ -393,7 +746,7 @@ on a specific thread running the phase completion step, or on a completion function's side effects occurring without \tcode{wait} having been called. -For example: +\begin{example} \begin{codeblock} auto b0 = std::barrier(1); b0.arrive(); @@ -405,6 +758,7 @@ assert(data == 1); // implementation-defined; previously well-defined b1.arrive(); // implementation-defined; previously well-defined \end{codeblock} +\end{example} \rSec1[diff.cpp17]{\Cpp{} and ISO \CppXVII{}} @@ -413,7 +767,8 @@ \pnum \indextext{summary!compatibility with ISO \CppXVII{}}% Subclause \ref{diff.cpp17} lists the differences between \Cpp{} and -ISO \CppXVII{} (ISO/IEC 14882:2017, \doccite{Programming Languages --- \Cpp{}}), +ISO \CppXVII{}, +in addition to those listed above, by the chapters of this document. \rSec2[diff.cpp17.lex]{\ref{lex}: lexical conventions} @@ -428,7 +783,7 @@ \tcode{module} or \tcode{import} may be interpreted differently in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} class module {}; module m1; // was variable declaration; now \grammarterm{module-declaration} @@ -438,6 +793,7 @@ import j1; // was variable declaration; now \grammarterm{module-import-declaration} ::import j2; // variable declaration \end{codeblock} +\end{example} \diffref{lex.header} \change @@ -448,12 +804,13 @@ When the identifier \tcode{import} is followed by a \tcode{<} character, a \grammarterm{header-name} token may be formed. -For example: +\begin{example} \begin{codeblock} template class import {}; import f(); // ill-formed; previously well-formed ::import g(); // OK \end{codeblock} +\end{example} \diffref{lex.key} \change @@ -501,7 +858,7 @@ Valid \CppXVII{} code that contains a \tcode{<=} token immediately followed by a \tcode{>} token may be ill-formed or have different semantics in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} namespace N { struct X {}; @@ -510,6 +867,7 @@ Y y; // ill-formed; previously well-formed } \end{codeblock} +\end{example} \diffref{lex.literal} \indextext{UTF-8}% @@ -524,7 +882,7 @@ UTF-8 string literals having type ``array of \tcode{const char}'' and UTF-8 character literals having type ``\tcode{char}'' is not valid in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} const auto *u8s = u8"text"; // \tcode{u8s} previously deduced as \tcode{const char*}; now deduced as \tcode{const char8_t*} const char *ps = u8s; // ill-formed; previously well-formed @@ -543,6 +901,7 @@ }; ct::type x; // ill-formed; previously well-formed. \end{codeblock} +\end{example} \rSec2[diff.cpp17.basic]{\ref{basic}: basics} @@ -555,7 +914,7 @@ \effect Valid ISO \CppXVII{} code may be ill-formed or have undefined behavior in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} int f() { int a = 123; @@ -564,6 +923,7 @@ return a; // undefined behavior; previously returned 123 } \end{codeblock} +\end{example} \diffref{intro.races} \change @@ -592,7 +952,7 @@ if those entities are only referenced in contexts that do not result in an odr-use. -\rSec2[diff.cpp17.dcl.dcl]{\ref{dcl.dcl}: declarations} +\rSec2[diff.cpp17.dcl.dcl]{\ref{dcl}: declarations} \diffref{dcl.typedef} \change @@ -602,12 +962,13 @@ Necessary for implementability. \effect Valid \CppXVII{} code may be ill-formed in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} typedef struct { void f() {} // ill-formed; previously well-formed } S; \end{codeblock} +\end{example} \diffref{dcl.fct.default} \change @@ -618,7 +979,7 @@ \effect Valid \CppXVII{} code may be ill-formed in this revision of \Cpp{}, with no diagnostic required. -For example: +\begin{example} \begin{codeblock} // Translation unit 1 int f(int a = 42); @@ -629,6 +990,7 @@ int g(); int main() { return g(); } // used to return 42 \end{codeblock} +\end{example} \diffref{dcl.init.aggr} \change @@ -641,7 +1003,7 @@ a type with a user-declared constructor may be ill-formed or have different semantics in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct A { // not an aggregate; previously an aggregate A() = delete; @@ -674,6 +1036,7 @@ Y y{X{}}; // copy constructor call; previously aggregate-initialization \end{codeblock} +\end{example} \diffref{dcl.init.list} \change @@ -684,10 +1047,11 @@ \effect Valid \CppXVII{} code may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} bool y[] = { "bc" }; // ill-formed; previously well-formed \end{codeblock} +\end{example} \rSec2[diff.cpp17.class]{\ref{class}: classes} @@ -704,7 +1068,7 @@ \effect Valid \CppXVII{} code may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct S { explicit (S)(const S&); // ill-formed; previously well-formed @@ -712,6 +1076,7 @@ explicit(true) (S)(int); // OK }; \end{codeblock} +\end{example} \diffref{class.ctor,class.dtor} \change @@ -722,7 +1087,7 @@ \effect Valid \CppXVII{} code may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} template struct A { @@ -731,6 +1096,7 @@ ~A(); // error: \grammarterm{simple-template-id} not allowed for destructor }; \end{codeblock} +\end{example} \diffref{class.copy.elision} \change @@ -744,7 +1110,7 @@ \effect Valid \CppXVII{} code may fail to compile or have different semantics in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct base { base(); @@ -776,6 +1142,7 @@ char c = *s.m; // undefined behavior; previously ok } \end{codeblock} +\end{example} \rSec2[diff.cpp17.over]{\ref{over}: overloading} @@ -792,7 +1159,7 @@ and an object of the other type invoke a different operator. Also, for certain types, equality or inequality expressions between two objects of that type become ambiguous. -For example: +\begin{example} \begin{codeblock} struct A { operator int() const; @@ -808,6 +1175,7 @@ (10 != x); // calls \#1, previously selected \#3 } \end{codeblock} +\end{example} \diffref{over.match.oper} \change @@ -817,7 +1185,7 @@ \effect Valid \CppXVII{} code that uses equality operators with conversion functions may be ill-formed or have different semantics in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct A { operator int() const { return 10; } @@ -833,6 +1201,7 @@ B b1; bool eq = (b1 == b1); // ambiguous; previously well-formed \end{codeblock} +\end{example} \rSec2[diff.cpp17.temp]{\ref{temp}: templates} @@ -843,18 +1212,18 @@ and for which name lookup finds nothing or finds a function will be treated as a \grammarterm{template-name} -in order to potentially cause argument dependent lookup to be performed. +in order to potentially cause argument-dependent lookup to be performed. \rationale It was problematic to call a function template with an explicit template argument list -via argument dependent lookup +via argument-dependent lookup because of the need to have a template with the same name visible via normal lookup. \effect Previously valid code that uses a function name as the left operand of a \tcode{<} operator would become ill-formed. -For example: +\begin{example} \begin{codeblock} struct A {}; bool operator<(void (*fp)(), A); @@ -865,6 +1234,7 @@ (f) < a; // still well-formed } \end{codeblock} +\end{example} \rSec2[diff.cpp17.except]{\ref{except}: exception handling} @@ -994,13 +1364,14 @@ Increase safety via preventing buffer overflow at compile time. \effect Valid \CppXVII{} code may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} auto p = new char[100]; char q[100]; std::cin >> std::setw(20) >> p; // ill-formed; previously well-formed std::cin >> std::setw(20) >> q; // OK \end{codeblock} +\end{example} \diffref{ostream.inserters.character} \indextext{UTF-8}% @@ -1012,13 +1383,14 @@ Valid \CppXVII{} code that passes UTF-8 literals to \tcode{basic_ostream::operator<<} or \tcode{basic_ostream::operator<<} is now ill-formed. -For example: +\begin{example} \begin{codeblock} std::cout << u8"text"; // previously called \tcode{operator<<(const char*)} and printed a string; // now ill-formed std::cout << u8'X'; // previously called \tcode{operator<<(char)} and printed a character; // now ill-formed \end{codeblock} +\end{example} \diffref{ostream.inserters.character} \change @@ -1032,13 +1404,14 @@ to \tcode{basic_ostream::operator<<} or that passes \keyword{char16_t} or \keyword{char32_t} characters or strings to \tcode{basic_ostream::operator<<} is now ill-formed. -For example: +\begin{example} \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} +\end{example} \diffref{fs.class.path} \change @@ -1049,12 +1422,13 @@ Valid \CppXVII{} code that depends on the \tcode{u8string()} and \tcode{generic_u8string()} member functions of \tcode{std::filesystem::path} returning \tcode{std::string} is not valid in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} std::filesystem::path p; std::string s1 = p.u8string(); // ill-formed; previously well-formed std::string s2 = p.generic_u8string(); // ill-formed; previously well-formed \end{codeblock} +\end{example} \rSec2[diff.cpp17.depr]{\ref{depr}: compatibility features} @@ -1153,7 +1527,7 @@ \pnum \indextext{summary!compatibility with ISO \CppXIV{}}% Subclause \ref{diff.cpp14} lists the differences between \Cpp{} and -ISO \CppXIV{} (ISO/IEC 14882:2014, \doccite{Programming Languages --- \Cpp{}}), +ISO \CppXIV{}, in addition to those listed above, by the chapters of this document. @@ -1169,8 +1543,9 @@ Valid \CppXIV{} code that uses trigraphs may not be valid or may have different semantics in this revision of \Cpp{}. Implementations may choose to translate trigraphs as specified in \CppXIV{} if they appear outside of a raw -string literal, as part of the \impldef{mapping input source file characters -to translation character set} mapping from input source file characters to +string literal, as part of the +\impldef{mapping input file characters to translation character set} +mapping from input source file characters to the translation character set. \diffref{lex.ppnumber} @@ -1184,11 +1559,12 @@ this revision of \Cpp{}. Specifically, character sequences like \tcode{0p+0} and \tcode{0e1_p+0} are three separate tokens each in \CppXIV{}, but one single token in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} #define F(a) b ## a int b0p = F(0p+0); // ill-formed; equivalent to ``\tcode{int b0p = b0p + 0;}\!'' in \CppXIV{} \end{codeblock} +\end{example} \rSec2[diff.cpp14.expr]{\ref{expr}: expressions} @@ -1216,7 +1592,7 @@ \tcode{::operator new(std::size_t, std::align_val_t)} is used instead. -\rSec2[diff.cpp14.dcl.dcl]{\ref{dcl.dcl}: declarations} +\rSec2[diff.cpp14.dcl.dcl]{\ref{dcl}: declarations} \diffref{dcl.stc} \indextext{\idxcode{register} storage class}% @@ -1237,11 +1613,12 @@ \effect Valid \CppXIV{} code may fail to compile or may change meaning in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} auto x1{1}; // was \tcode{std::initializer_list}, now \tcode{int} auto x2{1, 2}; // was \tcode{std::initializer_list}, now ill-formed \end{codeblock} +\end{example} \diffref{dcl.fct} \change @@ -1251,13 +1628,14 @@ \effect Valid \CppXIV{} code may fail to compile or change meaning in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} void g1() noexcept; void g2(); template int f(T *, T *); int x = f(g1, g2); // ill-formed; previously well-formed \end{codeblock} +\end{example} \diffref{dcl.init.aggr} \change @@ -1270,7 +1648,7 @@ revision of \Cpp{}; initialization from an empty initializer list will perform aggregate initialization instead of invoking a default constructor for the affected types. -For example: +\begin{example} \begin{codeblock} struct derived; struct base { @@ -1283,6 +1661,7 @@ derived d1{}; // error; the code was well-formed in \CppXIV{} derived d2; // still OK \end{codeblock} +\end{example} \rSec2[diff.cpp14.class]{\ref{class}: classes} @@ -1297,7 +1676,7 @@ that names a constructor now makes the corresponding base class constructors visible to initializations of the derived class rather than declaring additional derived class constructors. -For example: +\begin{example} \begin{codeblock} struct A { template A(T, typename T::type = 0); @@ -1311,21 +1690,22 @@ // which called \tcode{A(int)} due to substitution failure // in \tcode{A(long)}. \end{codeblock} +\end{example} \rSec2[diff.cpp14.temp]{\ref{temp}: templates} \diffref{temp.deduct.type} \change -Allowance to deduce from the type of a non-type template argument. +Allowance to deduce from the type of a constant template argument. \rationale In combination with the ability to declare -non-type template arguments with placeholder types, +constant template arguments with placeholder types, allows partial specializations to decompose -from the type deduced for the non-type template argument. +from the type deduced for the constant template argument. \effect Valid \CppXIV{} code may fail to compile or produce different results in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} template struct A; template int foo(A *) = delete; @@ -1334,6 +1714,7 @@ foo(p); // ill-formed; previously well-formed } \end{codeblock} +\end{example} \rSec2[diff.cpp14.except]{\ref{except}: exception handling} @@ -1414,12 +1795,13 @@ \effect Valid \CppXIV{} code may fail to compile or may change meaning in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} #include std::unique_ptr arr(new int[1]); std::shared_ptr ptr(std::move(arr)); // error: \tcode{int(*)[]} is not compatible with \tcode{int*} \end{codeblock} +\end{example} \rSec2[diff.cpp14.string]{\ref{strings}: strings library} @@ -1436,13 +1818,14 @@ will execute differently when called with a non-const string's \tcode{.data()} member in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} int f(char *) = delete; int f(const char *); string s; int x = f(s.data()); // ill-formed; previously well-formed \end{codeblock} +\end{example} \rSec2[diff.cpp14.containers]{\ref{containers}: containers library} @@ -1455,7 +1838,7 @@ Valid \CppXIV{} code that attempts to use associative containers having a comparison object with non-const function call operator may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} #include @@ -1472,6 +1855,7 @@ s.find(0); } \end{codeblock} +\end{example} \rSec2[diff.cpp14.depr]{\ref{depr}: compatibility features} @@ -1513,7 +1897,7 @@ \pnum \indextext{summary!compatibility with ISO \CppXI{}}% Subclause \ref{diff.cpp11} lists the differences between \Cpp{} and -ISO \CppXI{} (ISO/IEC 14882:2011, \doccite{Programming Languages --- \Cpp{}}), +ISO \CppXI{}, in addition to those listed above, by the chapters of this document. @@ -1530,13 +1914,14 @@ this revision of \Cpp{}, but the macro invocation produces different outcomes because the single quotes delimit a \grammarterm{character-literal} in \CppXI{}, whereas they are digit separators in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} #define M(x, ...) __VA_ARGS__ int x[2] = { M(1'2,3'4, 5) }; // \tcode{int x[2] = \{ 5 \};\ \ \ \ \ } --- \CppXI{} // \tcode{int x[2] = \{ 3'4, 5 \};} --- this revision of \Cpp{} \end{codeblock} +\end{example} \rSec2[diff.cpp11.basic]{\ref{basic}: basics} @@ -1572,7 +1957,7 @@ \effect Valid \CppXI{} code that relies on the conversions may behave differently in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct S { int x = 1; @@ -1591,8 +1976,9 @@ \end{codeblock} In \CppXI{}, the expression yields \tcode{sizeof(const char*)}. In this revision of \Cpp{}, it yields \tcode{sizeof(const char[1])}. +\end{example} -\rSec2[diff.cpp11.dcl.dcl]{\ref{dcl.dcl}: declarations} +\rSec2[diff.cpp11.dcl.dcl]{\ref{dcl}: declarations} \diffref{dcl.constexpr} \change @@ -1603,7 +1989,7 @@ the object. \effect Valid \CppXI{} code may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct S { constexpr const int &f(); @@ -1613,6 +1999,7 @@ This code is valid in \CppXI{} but invalid in this revision of \Cpp{} because it declares the same member function twice with different return types. +\end{example} \diffref{dcl.init.aggr} \change @@ -1622,7 +2009,7 @@ by aggregate initialization. \effect Valid \CppXI{} code may fail to compile or may change meaning in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} struct S { // Aggregate in \CppXIV{} onwards. int m = 1; @@ -1635,6 +2022,7 @@ S b{a}; // uses copy constructor in \CppXI{}, // performs aggregate initialization in this revision of \Cpp{} \end{codeblock} +\end{example} \rSec2[diff.cpp11.library]{\ref{library}: library introduction} @@ -1666,7 +2054,7 @@ \pnum \indextext{summary!compatibility with ISO \CppIII{}}% Subclause \ref{diff.cpp03} lists the differences between \Cpp{} and -ISO \CppIII{} (ISO/IEC 14882:2003, \doccite{Programming Languages --- \Cpp{}}), +ISO \CppIII{}, in addition to those listed above, by the chapters of this document. @@ -1683,11 +2071,12 @@ \tcode{u8R}, \tcode{u}, \tcode{uR}, \tcode{U}, \tcode{UR}, or \tcode{LR} will not be expanded when adjacent to a \grammarterm{string-literal} but will be interpreted as part of the \grammarterm{string-literal}. -For example: +\begin{example} \begin{codeblock} #define u8 "abc" const char* s = u8"def"; // Previously \tcode{"abcdef"}, now \tcode{"def"} \end{codeblock} +\end{example} \diffref{lex.pptoken} \change @@ -1697,7 +2086,7 @@ \effect Valid \CppIII{} code may fail to compile or produce different results in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} #define _x "there" "hello"_x // \#1 @@ -1706,6 +2095,7 @@ Previously, \#1 would have consisted of two separate preprocessing tokens and the macro \tcode{_x} would have been expanded. In this revision of \Cpp{}, \#1 consists of a single preprocessing token, so the macro is not expanded. +\end{example} \diffref{lex.key} \change @@ -1747,7 +2137,7 @@ \effect Valid \CppIII{} code may fail to compile or produce different results in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} void f(void *); // \#1 void f(...); // \#2 @@ -1755,6 +2145,29 @@ f(0*N); // calls \#2; used to call \#1 } \end{codeblock} +\end{example} + +\diffref{expr.typeid} +\change +Evaluation of operands in \keyword{typeid}. +\rationale +Introduce additional expression value categories. +\effect +Valid \CppIII{} code that uses xvalues as operands for \keyword{typeid} +may change behavior in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +void f() { + struct B { + B() {} + virtual ~B() { } + }; + + struct C { B b; }; + typeid(C().b); // unevaluated in \CppIII{}, evaluated in \CppXI{} +} +\end{codeblock} +\end{example} \diffref{expr.mul} \change @@ -1774,14 +2187,40 @@ \effect Valid \CppIII{} code may fail to compile or produce different results in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} bool b1 = new int && false; // previously \tcode{false}, now ill-formed struct S { operator int(); }; bool b2 = &S::operator int && false; // previously \tcode{false}, now ill-formed \end{codeblock} +\end{example} + +\diffref{expr.cond} +\change +Fewer copies in the conditional operator. +\rationale +Introduce additional expression value categories. +\effect +Valid \CppIII{} code that uses xvalues as operands for the conditional operator +may change behavior in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +void f() { + struct B { + B() {} + B(const B&) { } + }; + struct D : B {}; + + struct BB { B b; }; + struct DD { D d; }; + + true ? BB().b : DD().d; // additional copy in \CppIII{}, no copy or move in \CppXI{} +} +\end{codeblock} +\end{example} -\rSec2[diff.cpp03.dcl.dcl]{\ref{dcl.dcl}: declarations} +\rSec2[diff.cpp03.dcl.dcl]{\ref{dcl}: declarations} \diffref{dcl.spec} \change @@ -1803,13 +2242,36 @@ Catches bugs. \effect Valid \CppIII{} code may fail to compile in this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} int x[] = { 2.0 }; \end{codeblock} This code is valid in \CppIII{} but invalid in this revision of \Cpp{} because \tcode{double} to \tcode{int} is a narrowing conversion. +\end{example} + +\diffref{dcl.link} +\change +Names declared in an anonymous namespace +changed from external linkage to internal linkage; +language linkage applies to names with external linkage only. +\rationale +Alignment with user expectations. +\effect +Valid \CppIII{} code may violate the one-definition rule\iref{basic.def.odr} +in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +namespace { extern "C" { extern int x; } } // \#1, previously external linkage and C language linkage, + // now internal linkage and \Cpp{} language linkage +namespace A { extern "C" int x = 42; } // \#2, external linkage and C language linkage +int main(void) { return x; } +\end{codeblock} +This code is valid in \CppIII{}, +but \tcode{\#2} is not a definition for \tcode{\#1} +in this revision of \Cpp{}, violating the one-definition rule. +\end{example} \rSec2[diff.cpp03.class]{\ref{class}: classes} @@ -1857,7 +2319,7 @@ Change to semantics of well-defined expression. A valid \CppIII{} expression containing a right angle bracket (``\tcode{>}'') followed immediately by another right angle bracket may now be treated as closing two templates. -For example: +\begin{example} \begin{codeblock} template struct X { }; template struct Y { }; @@ -1866,6 +2328,7 @@ This code is valid in \CppIII{} because ``\tcode{>>}'' is a right-shift operator, but invalid in this revision of \Cpp{} because ``\tcode{>>}'' closes two templates. +\end{example} \diffref{temp.dep.candidate} \change @@ -1901,11 +2364,10 @@ \libheaderref{array}, \libheaderrefx{atomic}{atomics.syn}, \libheaderrefx{chrono}{time.syn}, -\libdeprheaderref{codecvt}, \libheaderrefx{condition_variable}{condition.variable.syn}, \libheaderrefx{forward_list}{forward.list.syn}, \libheaderref{future}, -\libheaderrefx{initializer_list}{initializer.list.syn}, +\libheaderrefxx{initializer_list}{initiali\-zer_list}{initializer.list.syn}, \libheaderref{mutex}, \libheaderrefx{random}{rand.synopsis}, \libheaderref{ratio}, @@ -1914,7 +2376,7 @@ \libheaderrefx{system_error}{system.error.syn}, \libheaderref{thread}, \libheaderref{tuple}, -\libheaderrefx{type\-index}{type.index.synopsis}, +\libheaderrefxx{typeindex}{type\-index}{type.index.synopsis}, \libheaderrefx{type_traits}{meta.type.synop}, \libheaderrefx{unordered_map}{unord.map.syn}, and @@ -1929,12 +2391,12 @@ invalid in this revision of \Cpp{}. \diffref{swappable.requirements} -\effect -Function \tcode{swap} moved to a different header +\change +Function \tcode{swap} moved to a different header. \rationale Remove dependency on \libheaderref{algorithm} for \tcode{swap}. \effect -Valid \CppIII{} code that has been compiled expecting swap to be in +Valid \CppIII{} code that has been compiled expecting \tcode{swap} to be in \libheaderref{algorithm} may have to instead include \libheaderref{utility}. \diffref{namespace.posix} @@ -1947,15 +2409,15 @@ \CppIII{} code that uses a top-level namespace \tcode{posix} may be invalid in this revision of \Cpp{}. -\diffref{res.on.macro.definitions} +\diffref{macro.names} \change Additional restrictions on macro names. \rationale Avoid hard to diagnose or non-portable constructs. \effect Names of attribute identifiers may not be used as macro names. Valid \CppIII{} -code that defines \tcode{override}, \tcode{final}, -\tcode{carries_dependency}, or \tcode{noreturn} as macros is invalid in this +code that defines \tcode{override}, \tcode{final}, or +\tcode{noreturn} as macros is invalid in this revision of \Cpp{}. \rSec2[diff.cpp03.language.support]{\ref{support}: @@ -2193,7 +2655,7 @@ Valid \CppIII{} code that relies on \tcode{std::ios_base} flag types being represented as \tcode{std::bitset} or as an integer type may fail to compile with this revision of \Cpp{}. -For example: +\begin{example} \begin{codeblock} #include @@ -2202,14 +2664,15 @@ std::cout.setf(flag); // error: \tcode{setf} does not take argument of type \tcode{int} } \end{codeblock} +\end{example} -\rSec1[diff.iso]{\Cpp{} and ISO C} +\rSec1[diff.iso]{\Cpp{} and C} \rSec2[diff.iso.general]{General} \pnum -\indextext{summary!compatibility with ISO C}% -Subclause \ref{diff.iso} lists the differences between \Cpp{} and ISO C, +\indextext{summary!compatibility with C}% +Subclause \ref{diff.iso} lists the differences between \Cpp{} and C, in addition to those listed above, by the chapters of this document. @@ -2217,7 +2680,7 @@ \diffref{lex.key} \change -New Keywords\\ +New Keywords.\\ New keywords are added to \Cpp{}; see \ref{lex.key}. \rationale @@ -2225,7 +2688,7 @@ semantics of \Cpp{}. \effect Change to semantics of well-defined feature. -Any ISO C programs that used any of these keywords as identifiers +Any C programs that used any of these keywords as identifiers are not valid \Cpp{} programs. \difficulty Syntactic transformation. @@ -2240,7 +2703,8 @@ Type of \grammarterm{character-literal} is changed from \tcode{int} to \tcode{char}. \rationale This is needed for improved overloaded function argument type -matching. For example: +matching. +\begin{example} \begin{codeblock} int function( int i ); int function( char c ); @@ -2249,9 +2713,10 @@ \end{codeblock} It is preferable that this call match the second version of function rather than the first. +\end{example} \effect Change to semantics of well-defined feature. -ISO C programs which depend on +C programs which depend on \begin{codeblock} sizeof('x') == sizeof(int) \end{codeblock} @@ -2321,16 +2786,18 @@ \diffref{basic.def} \change \Cpp{} does not have ``tentative definitions'' as in C.\\ -E.g., at file scope, +\begin{example} +At file scope, \begin{codeblock} int i; int i; \end{codeblock} is valid in C, invalid in \Cpp{}. +\end{example} This makes it impossible to define mutually referential file-local objects with static storage duration, if initializers are restricted to the syntactic forms of C\@. -For example, +\begin{example} \begin{codeblock} struct X { int i; struct X* next; }; @@ -2338,6 +2805,7 @@ static struct X b = { 0, &a }; static struct X a = { 1, &b }; \end{codeblock} +\end{example} \rationale This avoids having different initialization rules for fundamental types and user-defined types. @@ -2355,7 +2823,7 @@ \diffref{basic.scope} \change A \keyword{struct} is a scope in \Cpp{}, not in C. -For example, +\begin{example} \begin{codeblock} struct X { struct Y { int a; } b; @@ -2363,6 +2831,7 @@ struct Y c; \end{codeblock} is valid in C but not in \Cpp{}, which would require \tcode{X::Y c;}. +\end{example} \rationale Class scope is crucial to \Cpp{}, and a struct is a class. \effect @@ -2432,6 +2901,7 @@ \diffref{conv.ptr} \change Converting \tcode{\keyword{void}*} to a pointer-to-object type requires casting. +\begin{example} \begin{codeblock} char a[10]; void* b=a; @@ -2440,9 +2910,10 @@ } \end{codeblock} -ISO C accepts this usage of pointer to \keyword{void} being assigned +C accepts this usage of pointer to \keyword{void} being assigned to a pointer to object type. \Cpp{} does not. +\end{example} \rationale \Cpp{} tries harder than C to enforce compile-time type safety. \effect @@ -2450,26 +2921,57 @@ \difficulty Can be automated. Violations will be diagnosed by the \Cpp{} translator. -The -fix is to add a cast. -For example: +The fix is to add a cast. +\begin{example} \begin{codeblock} char* c = (char*) b; \end{codeblock} +\end{example} \howwide This is fairly widely used but it is good programming practice to add the cast when assigning pointer-to-void to pointer-to-object. -Some ISO C translators will give a warning +Some C translators will give a warning if the cast is not used. +\diffref{expr.arith.conv} +\change +Operations mixing a value of an enumeration type and a value of a different +enumeration type or of a floating-point type are not valid. +\begin{example} +\begin{codeblock} +enum E1 { e }; +enum E2 { f }; +int b = e <= 3.7; // valid in C; ill-formed in \Cpp{} +int k = f - e; // valid in C; ill-formed in \Cpp{} +int x = 1 ? e : f; // valid in C; ill-formed in \Cpp{} +\end{codeblock} +\end{example} +\rationale +Reinforcing type safety in \Cpp{}. +\effect +Well-formed C code will not compile with this International Standard. +\difficulty +Violations will be diagnosed by the \Cpp{} translator. +The original behavior can be restored with a cast or integral promotion. +\begin{example} +\begin{codeblock} +enum E1 { e }; +enum E2 { f }; +int b = (int)e <= 3.7; +int k = +f - e; +\end{codeblock} +\end{example} +\howwide +Uncommon. + \diffref{expr.post.incr,expr.pre.incr} \change Decrement operator is not allowed with \keyword{bool} operand. \rationale Feature with surprising semantics. \effect -A valid ISO C expression utilizing the decrement operator on +A valid C expression utilizing the decrement operator on a \keyword{bool} lvalue (for instance, via the C typedef in \libheaderref{stdbool.h}) is ill-formed in \Cpp{}. @@ -2478,11 +2980,12 @@ \change In \Cpp{}, types can only be defined in declarations, not in expressions.\\ In C, a \keyword{sizeof} expression or cast expression may define a new type. -For example, +\begin{example} \begin{codeblock} p = (void*)(struct x {int i;} *)0; \end{codeblock} defines a new type, struct \tcode{x}. +\end{example} \rationale This prohibition helps to clarify the location of definitions in the source code. @@ -2493,7 +2996,31 @@ \howwide Seldom. -\diffref{expr.cond,expr.ass,expr.comma} +\diffref{expr.rel,expr.eq} +\change +C allows directly comparing two objects of array type; \Cpp{} does not. +\rationale +The behavior is confusing because it compares not the contents of the two +arrays, but their addresses. +\effect +Deletion of semantically well-defined feature that had unspecified behavior +in common use cases. +\difficulty +Violations will be diagnosed by the \Cpp{} translator. The original behavior +can be replicated by explicitly casting either array to a pointer, such as by +using a unary \tcode{+}. +\begin{example} +\begin{codeblock} +int arr1[5]; +int arr2[5]; +int same = arr1 == arr2; // valid C, ill-formed C++ +int idem = arr1 == +arr2; // valid in both C and C++ +\end{codeblock} +\end{example} +\howwide +Rare. + +\diffref{expr.cond,expr.assign,expr.comma} \indextext{conversion!lvalue-to-rvalue}% \indextext{rvalue!lvalue conversion to}% \indextext{lvalue}% @@ -2507,7 +3034,7 @@ Change to semantics of well-defined feature. Some C expressions that implicitly rely on lvalue-to-rvalue conversions will yield different results. -For example, +\begin{example} \begin{codeblock} char arr[100]; sizeof(0, arr) @@ -2517,12 +3044,13 @@ in \Cpp{} and \tcode{sizeof(char*)} in C. +\end{example} \difficulty Programs must add explicit casts to the appropriate rvalue. \howwide Rare. -\rSec2[diff.stat]{\ref{stmt.stmt}: statements} +\rSec2[diff.stat]{\ref{stmt}: statements} \diffref{stmt.switch,stmt.goto} \change @@ -2570,7 +3098,7 @@ For several years, many existing C implementations have produced warnings in this case. -\rSec2[diff.dcl]{\ref{dcl.dcl}: declarations} +\rSec2[diff.dcl]{\ref{dcl}: declarations} \diffref{dcl.stc} \change @@ -2578,12 +3106,13 @@ Using these specifiers with type declarations is illegal in \Cpp{}. In C, these specifiers are ignored when used on type declarations. -Example: +\begin{example} \begin{codeblock} static struct S { // valid C, invalid in \Cpp{} int i; }; \end{codeblock} +\end{example} \rationale Storage class specifiers don't have any meaning when associated @@ -2618,23 +3147,25 @@ same name). In C, a \grammarterm{typedef-name} and a struct tag name declared in the same scope can have the same name (because they have different name spaces). -Example: +\begin{example} \begin{codeblock} typedef struct name1 { @\commentellip@ } name1; // valid C and \Cpp{} struct name { @\commentellip@ }; typedef int name; // valid C, invalid \Cpp{} \end{codeblock} +\end{example} \rationale For ease of use, \Cpp{} doesn't require that a type name be prefixed with the keywords \keyword{class}, \keyword{struct} or \keyword{union} when used in object declarations or type casts. -Example: +\begin{example} \begin{codeblock} class name { @\commentellip@ }; name i; // \tcode{i} has type \tcode{class name} \end{codeblock} +\end{example} \effect Deletion of semantically well-defined feature. @@ -2661,12 +3192,13 @@ \change The keyword \keyword{auto} cannot be used as a storage class specifier. -Example: +\begin{example} \begin{codeblock} void f() { auto int x; // valid C, invalid \Cpp{} } \end{codeblock} +\end{example} \rationale Allowing the use of \keyword{auto} to deduce the type @@ -2684,15 +3216,16 @@ In \Cpp{}, a function declared with an empty parameter list takes no arguments. In C, an empty parameter list means that the number and type of the function arguments are unknown. -Example: +\begin{example} \begin{codeblock} int f(); // means \tcode{int f(void)} in \Cpp{} // \tcode{int f(} unknown \tcode{)} in C \end{codeblock} +\end{example} \rationale -This is to avoid erroneous function calls (i.e., function calls -with the wrong number or type of arguments). +This is to avoid function calls +with the wrong number or type of arguments. \effect Change to semantics of well-defined feature. This feature was marked as ``obsolescent'' in C. @@ -2711,11 +3244,12 @@ In \Cpp{}, types may not be defined in return or parameter types. In C, these type definitions are allowed. -Example: +\begin{example} \begin{codeblock} void f( struct S { int a; } arg ) {} // valid C, invalid \Cpp{} enum E { A, B, C } f() {} // valid C, invalid \Cpp{} \end{codeblock} +\end{example} \rationale When comparing types in different translation units, \Cpp{} relies @@ -2758,7 +3292,7 @@ designated and non-designated initializers cannot be mixed in the same initializer list. -Example: +\begin{example} \begin{codeblock} struct A { int x, y; }; struct B { struct A a; }; @@ -2767,6 +3301,7 @@ struct B b = {.a.x = 0}; // valid C, invalid \Cpp{} struct A c = {.x = 1, 2}; // valid C, invalid \Cpp{} \end{codeblock} +\end{example} \rationale In \Cpp{}, members are destroyed in reverse construction order and the elements of an initializer list are evaluated in lexical order, @@ -2788,10 +3323,11 @@ number of elements in the array. In C, an array can be initialized with a string even if the array is not large enough to contain the string-terminating \tcode{'\textbackslash 0'}. -Example: +\begin{example} \begin{codeblock} char array[4] = "abcd"; // valid C, invalid \Cpp{} \end{codeblock} +\end{example} \rationale When these non-terminated arrays are manipulated by standard string functions, there is potential for major catastrophe. @@ -2810,11 +3346,12 @@ \Cpp{} objects of enumeration type can only be assigned values of the same enumeration type. In C, objects of enumeration type can be assigned values of any integral type. -Example: +\begin{example} \begin{codeblock} enum color { red, blue, green }; enum color c = 1; // valid C, invalid \Cpp{} \end{codeblock} +\end{example} \rationale The type-safe nature of \Cpp{}. @@ -2831,13 +3368,14 @@ \change In \Cpp{}, the type of an enumerator is its enumeration. In C, the type of an enumerator is \keyword{int}. -Example: +\begin{example} \begin{codeblock} enum e { A }; sizeof(A) == sizeof(int) // in C sizeof(A) == sizeof(e) // in \Cpp{} /* and @sizeof(int)@ is not necessarily equal to @sizeof(e)@ */ \end{codeblock} +\end{example} \rationale In \Cpp{}, an enumeration is a distinct type. @@ -2858,12 +3396,14 @@ an \grammarterm{alignment-specifier} is an \grammarterm{attribute-specifier}. In C, an \grammarterm{alignment-specifier} is a \gterm{declaration-specifier}. -Example: +\begin{example} \begin{codeblock} #include unsigned alignas(8) int x; // valid C, invalid \Cpp{} unsigned int y alignas(8); // valid \Cpp{}, invalid C \end{codeblock} +\end{example} + \rationale \Cpp{} requires unambiguous placement of the \grammarterm{alignment-specifier}. \effect @@ -2882,7 +3422,7 @@ scope. In C, an inner scope declaration of a struct tag name never hides the name of an object or function in an outer scope. -Example: +\begin{example} \begin{codeblock} int x[99]; void f() { @@ -2891,6 +3431,7 @@ /* size of the struct in @\textit{\textrm{\Cpp{}}}@ */ } \end{codeblock} +\end{example} \rationale This is one of the few incompatibilities between C and \Cpp{} that can be attributed to the new \Cpp{} name space definition where a @@ -2921,7 +3462,8 @@ The implicitly-declared copy constructor and implicitly-declared copy assignment operator cannot make a copy of a volatile lvalue. -For example, the following is valid in ISO C: +\begin{example} +The following is valid in C: \begin{codeblock} struct X { int i; }; volatile struct X x1 = {0}; @@ -2929,6 +3471,7 @@ struct X x3; x3 = x1; // also invalid \Cpp{} \end{codeblock} +\end{example} \rationale Several alternatives were debated at length. @@ -2981,13 +3524,14 @@ In \Cpp{}, the name of a nested class is local to its enclosing class. In C the name of the nested class belongs to the same scope as the name of the outermost enclosing class. -Example: +\begin{example} \begin{codeblock} struct X { struct Y { @\commentellip@ } y; }; struct Y yy; // valid C, invalid \Cpp{} \end{codeblock} +\end{example} \rationale \Cpp{} classes have member functions which require that classes establish scopes. @@ -3005,13 +3549,14 @@ To make the struct type name visible in the scope of the enclosing struct, the struct tag can be declared in the scope of the enclosing struct, before the enclosing struct is defined. -Example: +\begin{example} \begin{codeblock} struct Y; // \tcode{struct Y} and \tcode{struct X} are at the same scope struct X { struct Y { @\commentellip@ } y; }; \end{codeblock} +\end{example} All the definitions of C struct types enclosed in other struct definitions and accessed outside the scope of the enclosing @@ -3025,7 +3570,7 @@ \change In \Cpp{}, a \grammarterm{typedef-name} may not be redeclared in a class definition after being used in that definition. -Example: +\begin{example} \begin{codeblock} typedef int I; struct S { @@ -3033,6 +3578,7 @@ int I; // valid C, invalid \Cpp{} }; \end{codeblock} +\end{example} \rationale When classes become complicated, allowing such a redefinition after the type has been used can create confusion for \Cpp{} @@ -3052,7 +3598,7 @@ Whether \mname{STDC} is defined and if so, what its value is, are \impldef{definition and meaning of \mname{STDC}}. \rationale -\Cpp{} is not identical to ISO C\@. +\Cpp{} is not identical to C\@. Mandating that \mname{STDC} be defined would require that translators make an incorrect claim. \effect @@ -3146,7 +3692,6 @@ by \libheaderref{iso646.h}. \rSec3[diff.header.stdalign.h]{Header \tcode{}} -\indexhdr{stdalign.h}% \pnum The token \keyword{alignas} is a keyword in \Cpp{}\iref{lex.key}, @@ -3154,7 +3699,6 @@ by \libheaderref{stdalign.h}. \rSec3[diff.header.stdbool.h]{Header \tcode{}} -\indexhdr{stdbool.h}% \pnum The tokens \keyword{bool}, \keyword{true}, and \keyword{false} diff --git a/source/concepts.tex b/source/concepts.tex index 0508cb542b..4d848e8fd6 100644 --- a/source/concepts.tex +++ b/source/concepts.tex @@ -420,7 +420,7 @@ 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_reference_with}} -only if: +only if \begin{itemize} \item \tcode{C(t1)} equals \tcode{C(t2)} if and only if \tcode{t1} equals \tcode{t2}, and @@ -473,7 +473,7 @@ 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_with}} -only if: +only if \begin{itemize} \item \tcode{C(t1)} equals \tcode{C(t2)} if and only if \tcode{t1} equals \tcode{t2}, and @@ -881,7 +881,7 @@ \pnum Let \tcode{e} be an expression such that \tcode{decltype((e))} is \tcode{T}. -\tcode{T} models \exposconcept{boolean-testable-impl} only if: +\tcode{T} models \exposconcept{boolean-testable-impl} only if \begin{itemize} \item @@ -1024,7 +1024,7 @@ let \tcode{u1} and \tcode{u2} be equality-preserving expressions that are lvalues of type \tcode{remove_cvref_t}. \tcode{T} and \tcode{U} model -\tcode{\exposconcept{comparison-common-type-with}} only if: +\tcode{\exposconcept{comparison-common-type-with}} only if \begin{itemize} \item \tcode{\exposid{CONVERT_TO_LVALUE}(t1)} equals @@ -1222,7 +1222,7 @@ \rSec2[concepts.callable.general]{General} \pnum -The concepts in subclause \ref{concepts.callable} describe the requirements on function +The concepts in \ref{concepts.callable} describe the requirements on function objects\iref{function.objects} and their arguments. \rSec2[concept.invocable]{Concept \cname{invocable}} diff --git a/source/config.tex b/source/config.tex index 3867bcb2bd..3937ed3116 100644 --- a/source/config.tex +++ b/source/config.tex @@ -2,12 +2,15 @@ %%-------------------------------------------------- %% Version numbers \newcommand{\docno}{Dxxxx} -\newcommand{\prevdocno}{N4964} +\newcommand{\prevdocno}{N5008} \newcommand{\cppver}{202302L} %% Release date \newcommand{\reldate}{\today} +%% Core chapters +\newcommand{\lastcorechapter}{cpp} + %% Library chapters \newcommand{\firstlibchapter}{support} -\newcommand{\lastlibchapter}{thread} +\newcommand{\lastlibchapter}{exec} diff --git a/source/containers.tex b/source/containers.tex index 69494898fa..947cfee6d8 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -20,7 +20,8 @@ \ref{container.requirements} & Requirements & \\ \rowsep \ref{sequences} & Sequence containers & \tcode{}, \tcode{}, \tcode{}, - \tcode{}, \tcode{} \\ \rowsep + \tcode{}, \\ & & + \tcode{}, \tcode{}, \tcode{} \\ \rowsep \ref{associative} & Associative containers & \tcode{}, \tcode{} \\ \rowsep \ref{unord} & Unordered associative containers & @@ -74,7 +75,7 @@ \rSec3[container.intro.reqmts]{Introduction} \pnum -In subclause \ref{container.requirements.general}, +In \ref{container.requirements.general}, \begin{itemize} \item \tcode{X} denotes a container class containing objects of type \tcode{T}, @@ -111,6 +112,7 @@ \indexlibrarymemberx{array}{#1}% \indexlibrarymemberx{deque}{#1}% \indexlibrarymemberx{forward_list}{#1}% +\indexlibrarymemberx{hive}{#1}% \indexlibrarymemberx{list}{#1}% \indexlibrarymemberx{vector}{#1}% \indexlibrarymemberx{map}{#1}% @@ -121,6 +123,10 @@ \indexlibrarymemberx{unordered_set}{#1}% \indexlibrarymemberx{unordered_multiset}{#1}% \indexlibrarymemberx{unordered_multimap}{#1}% +\indexlibrarymemberx{flat_map}{#1}% +\indexlibrarymemberx{flat_set}{#1}% +\indexlibrarymemberx{flat_multiset}{#1}% +\indexlibrarymemberx{flat_multimap}{#1}% } \pnum @@ -262,7 +268,7 @@ \pnum \complexity -Linear for \tcode{array} and constant for all other standard containers. +Linear for \tcode{array} and \tcode{inplace_vector} and constant for all other standard containers. \end{itemdescr} \indexcont{operator=}% @@ -421,7 +427,25 @@ Constant. \end{itemdescr} -\indexcont{operator==}% +% hive is excluded here +\indexlibrarymisc{\idxcode{operator==}}{containers}% +\indexlibrarymemberx{array}{operator==}% +\indexlibrarymemberx{deque}{operator==}% +\indexlibrarymemberx{forward_list}{operator==}% +\indexlibrarymemberx{list}{operator==}% +\indexlibrarymemberx{vector}{operator==}% +\indexlibrarymemberx{map}{operator==}% +\indexlibrarymemberx{set}{operator==}% +\indexlibrarymemberx{multiset}{operator==}% +\indexlibrarymemberx{multimap}{operator==}% +\indexlibrarymemberx{unordered_map}{operator==}% +\indexlibrarymemberx{unordered_set}{operator==}% +\indexlibrarymemberx{unordered_multiset}{operator==}% +\indexlibrarymemberx{unordered_multimap}{operator==}% +\indexlibrarymemberx{flat_map}{operator==}% +\indexlibrarymemberx{flat_set}{operator==}% +\indexlibrarymemberx{flat_multiset}{operator==}% +\indexlibrarymemberx{flat_multimap}{operator==}% \begin{itemdecl} c == b \end{itemdecl} @@ -452,7 +476,25 @@ \tcode{==} is an equivalence relation. \end{itemdescr} -\indexcont{operator"!=}% +% hive is excluded here +\indexlibrarymisc{\idxcode{operator"!=}}{containers}% +\indexlibrarymemberx{array}{operator"!=}% +\indexlibrarymemberx{deque}{operator"!=}% +\indexlibrarymemberx{forward_list}{operator"!=}% +\indexlibrarymemberx{list}{operator"!=}% +\indexlibrarymemberx{vector}{operator"!=}% +\indexlibrarymemberx{map}{operator"!=}% +\indexlibrarymemberx{set}{operator"!=}% +\indexlibrarymemberx{multiset}{operator"!=}% +\indexlibrarymemberx{multimap}{operator"!=}% +\indexlibrarymemberx{unordered_map}{operator"!=}% +\indexlibrarymemberx{unordered_set}{operator"!=}% +\indexlibrarymemberx{unordered_multiset}{operator"!=}% +\indexlibrarymemberx{unordered_multimap}{operator"!=}% +\indexlibrarymemberx{flat_map}{operator"!=}% +\indexlibrarymemberx{flat_set}{operator"!=}% +\indexlibrarymemberx{flat_multiset}{operator"!=}% +\indexlibrarymemberx{flat_multimap}{operator"!=}% \begin{itemdecl} c != b \end{itemdecl} @@ -479,7 +521,8 @@ \pnum \complexity -Linear for \tcode{array} and constant for all other standard containers. +Linear for \tcode{array} and \tcode{inplace_vector}, and +constant for all other standard containers. \end{itemdescr} \begin{itemdecl} @@ -617,7 +660,8 @@ \pnum The expression \tcode{a.swap(b)}, for containers \tcode{a} and \tcode{b} of a standard -container type other than \tcode{array}, shall exchange the values of \tcode{a} and +container type other than \tcode{array} and \tcode{inplace_vector}, +shall exchange the values of \tcode{a} and \tcode{b} without invoking any move, copy, or swap operations on the individual container elements. Any \tcode{Compare}, \tcode{Pred}, or \tcode{Hash} types @@ -637,7 +681,7 @@ swap. \pnum -Unless otherwise specified (see~\ref{associative.reqmts.except}, \ref{unord.req.except}, \ref{deque.modifiers}, and +Unless otherwise specified (see~\ref{associative.reqmts.except}, \ref{unord.req.except}, \ref{deque.modifiers}, \ref{inplace.vector.modifiers}, and \ref{vector.modifiers}) all container types defined in this Clause meet the following additional requirements: @@ -720,6 +764,7 @@ \indexlibrarymisc{\idxcode{#1}}{reversible containers}% \indexlibrarymemberx{array}{#1}% \indexlibrarymemberx{deque}{#1}% +\indexlibrarymemberx{hive}{#1}% \indexlibrarymemberx{list}{#1}% \indexlibrarymemberx{vector}{#1}% \indexlibrarymemberx{map}{#1}% @@ -730,6 +775,10 @@ \indexlibrarymemberx{unordered_set}{#1}% \indexlibrarymemberx{unordered_multiset}{#1}% \indexlibrarymemberx{unordered_multimap}{#1}% +\indexlibrarymemberx{flat_map}{#1}% +\indexlibrarymemberx{flat_set}{#1}% +\indexlibrarymemberx{flat_multiset}{#1}% +\indexlibrarymemberx{flat_multimap}{#1}% } \pnum @@ -887,7 +936,7 @@ \pnum \expects -Either \tcode{<=>} is defined for values of type (possibly const) \tcode{T}, +Either \tcode{T} models \libconcept{three_way_comparable}, or \tcode{<} is defined for values of type (possibly const) \tcode{T} and \tcode{<} is a total ordering relationship. @@ -908,7 +957,8 @@ \rSec3[container.alloc.reqmts]{Allocator-aware containers} \pnum -Except for \tcode{array}, all of the containers defined in \ref{containers}, +Except for \tcode{array} and \tcode{inplace_vector}, +all of the containers defined in \ref{containers}, \ref{stacktrace.basic}, \ref{basic.string}, and \ref{re.results} meet the additional requirements of an \defnadj{allocator-aware}{container}, as described below. @@ -919,7 +969,9 @@ and an \tcode{allocator_type} identical to \tcode{allocator_traits::rebind_alloc} and given an lvalue \tcode{m} of type \tcode{A}, a pointer \tcode{p} of type \tcode{T*}, -an expression \tcode{v} of type \tcode{T} or \tcode{const T}, +an expression \tcode{v} that denotes +an lvalue of type \tcode{T} or \tcode{const T} or +an rvalue of type \tcode{const T}, and an rvalue \tcode{rv} of type \tcode{T}, the following terms are defined. If \tcode{X} is not allocator-aware or is a specialization of \tcode{basic_string}, @@ -956,7 +1008,7 @@ and its evaluation causes the following postcondition to hold: The value of \tcode{*p} is equivalent to the value of \tcode{rv} before the evaluation. \begin{note} -\tcode{rv} remains a valid object. Its state is unspecified +\tcode{rv} remains a valid object. Its state is unspecified. \end{note} \item @@ -1024,6 +1076,7 @@ \indexlibrarymisc{\idxcode{#1}}{allocator-aware containers}% \indexlibrarymemberx{deque}{#1}% \indexlibrarymemberx{forward_list}{#1}% +\indexlibrarymemberx{hive}{#1}% \indexlibrarymemberx{list}{#1}% \indexlibrarymemberx{vector}{#1}% \indexlibrarymemberx{map}{#1}% @@ -1115,7 +1168,7 @@ \pnum \ensures -\tcode{u == t}, \tcode{u.get_allocator() == m} +\tcode{u == t}, \tcode{u.get_allocator() == m}. \pnum \complexity @@ -1261,10 +1314,15 @@ \pnum A sequence container organizes a finite set of objects, all of the same type, into a strictly -linear arrangement. The library provides four basic kinds of sequence containers: -\tcode{vector}, \tcode{forward_list}, \tcode{list}, and \tcode{deque}. In addition, -\tcode{array} is provided as a sequence container which provides limited sequence operations -because it has a fixed number of elements. The library also provides container adaptors that +linear arrangement. The library provides the following basic kinds of sequence containers: +\tcode{vector}, \tcode{inplace_vector}, +\tcode{forward_list}, \tcode{list}, and \tcode{deque}. +In addition, +\tcode{array} and \tcode{hive} are provided as sequence containers +which provide limited sequence operations, +in \tcode{array}'s case because it has a fixed number of elements, and +in \tcode{hive}'s case because insertion order is unspecified. +The library also provides container adaptors that make it easy to construct abstract data types, such as \tcode{stack}s, \tcode{queue}s, @@ -1293,7 +1351,7 @@ denote iterators that meet the \oldconcept{InputIterator} requirements and refer to elements implicitly convertible to \tcode{value_type}, \item -\tcode{[i, j)} denotes a valid range, +\range{i}{j} denotes a valid range, \item \tcode{rg} denotes a value of a type \tcode{R} that models \tcode{\exposconcept{container-compatible-range}}, @@ -1306,7 +1364,7 @@ \item \tcode{q} denotes a valid dereferenceable constant iterator to \tcode{a}, \item -\tcode{[q1, q2)} denotes a valid range of constant iterators in \tcode{a}, +\range{q1}{q2} denotes a valid range of constant iterators in \tcode{a}, \item \tcode{t} denotes an lvalue or a const rvalue of \tcode{X::value_type}, and \item @@ -1368,7 +1426,7 @@ \pnum \effects -Constructs a sequence container equal to the range \tcode{[i, j)}. +Constructs a sequence container equal to the range \range{i}{j}. Each iterator in the range \range{i}{j} is dereferenced exactly once. \pnum @@ -1387,7 +1445,10 @@ from \tcode{*ranges::begin(rg)}. For \tcode{vector}, if \tcode{R} models -neither \tcode{ranges::\libconcept{sized_range}} nor \tcode{ranges::\libconcept{forward_range}}, +\tcode{ranges::\libconcept{approximately_sized_range}} +but not \tcode{ranges::\libconcept{sized_range}} or models +\tcode{ranges::\libconcept{input_range}} +but not \tcode{ranges::\libconcept{forward_range}}, \tcode{T} is also \oldconcept{MoveInsertable} into \tcode{X}. \pnum @@ -1395,6 +1456,12 @@ Constructs a sequence container equal to the range \tcode{rg}. Each iterator in the range \tcode{rg} is dereferenced exactly once. +\pnum +\recommended +If \tcode{R} models \tcode{ranges::\libconcept{approximately_sized_range}} and +\tcode{ranges::distance(\linebreak{}rg) <= ranges::reserve_hint(rg)} is \tcode{true}, +an implementation should not perform any reallocation. + \pnum \ensures \tcode{distance(begin(), end()) == ranges::distance(rg)} is \tcode{true}. @@ -1447,7 +1514,7 @@ \pnum \expects \tcode{T} is \oldconcept{EmplaceConstructible} into \tcode{X} from \tcode{args}. -For \tcode{vector} and \tcode{deque}, +For \tcode{vector}, \tcode{inplace_vector}, and \tcode{deque}, \tcode{T} is also \oldconcept{MoveInsertable} into \tcode{X} and \oldconcept{MoveAssignable}. @@ -1462,8 +1529,7 @@ \pnum \returns -An iterator that points to -the new element constructed from \tcode{args} into \tcode{a}. +An iterator that points to the new element. \end{itemdescr} \indexcont{insert}% @@ -1479,7 +1545,7 @@ \pnum \expects \tcode{T} is \oldconcept{CopyInsertable} into \tcode{X}. -For \tcode{vector} and \tcode{deque}, +For \tcode{vector}, \tcode{inplace_vector}, and \tcode{deque}, \tcode{T} is also \oldconcept{CopyAssignable}. \pnum @@ -1503,7 +1569,7 @@ \pnum \expects \tcode{T} is \oldconcept{MoveInsertable} into \tcode{X}. -For \tcode{vector} and \tcode{deque}, +For \tcode{vector}, \tcode{inplace_vector}, and \tcode{deque}, \tcode{T} is also \oldconcept{MoveAssignable}. \pnum @@ -1552,18 +1618,18 @@ \pnum \expects \tcode{T} is \oldconcept{EmplaceConstructible} into \tcode{X} from \tcode{*i}. -For \tcode{vector} and \tcode{deque}, +For \tcode{vector}, \tcode{inplace_vector}, and \tcode{deque}, \tcode{T} is also \oldconcept{MoveInsertable} into \tcode{X}, and \tcode{T} meets the \oldconcept{MoveConstructible}, -\oldconcept{MoveAssignable}, and +\oldconcept{MoveAs\-signable}, and \oldconcept{Swappable}\iref{swappable.requirements} requirements. Neither \tcode{i} nor \tcode{j} are iterators into \tcode{a}. \pnum \effects -Inserts copies of elements in \tcode{[i, j)} before \tcode{p}. +Inserts copies of elements in \range{i}{j} before \tcode{p}. Each iterator in the range \range{i}{j} shall be dereferenced exactly once. \pnum @@ -1587,12 +1653,12 @@ \expects \tcode{T} is \oldconcept{EmplaceConstructible} into \tcode{X} from \tcode{*ranges::begin(rg)}. -For \tcode{vector} and \tcode{deque}, +For \tcode{vector}, \tcode{inplace_vector}, and \tcode{deque}, \tcode{T} is also \oldconcept{MoveInsertable} into \tcode{X}, and \tcode{T} meets the -\oldconcept{MoveConstructible}, -\oldconcept{Move\-Assignable}, and +\oldconcept{Move\-Constructible}, +\oldconcept{MoveAssignable}, and \oldconcept{Swappable}\iref{swappable.requirements} requirements. \tcode{rg} and \tcode{a} do not overlap. @@ -1630,7 +1696,7 @@ \pnum \expects -For \tcode{vector} and \tcode{deque}, +For \tcode{vector}, \tcode{inplace_vector}, and \tcode{deque}, \tcode{T} is \oldconcept{MoveAssignable}. \pnum @@ -1655,11 +1721,12 @@ \pnum \expects -For \tcode{vector} and \tcode{deque}, \tcode{T} is \oldconcept{MoveAssignable}. +For \tcode{vector}, \tcode{inplace_vector}, and \tcode{deque}, +\tcode{T} is \oldconcept{MoveAssignable}. \pnum \effects -Erases the elements in the range \tcode{[q1, q2)}. +Erases the elements in the range \range{q1}{q2}. \pnum \returns @@ -1716,7 +1783,7 @@ \pnum \effects -Replaces elements in \tcode{a} with a copy of \tcode{[i, j)}. +Replaces elements in \tcode{a} with a copy of \range{i}{j}. Invalidates all references, pointers and iterators referring to the elements of \tcode{a}. For \tcode{vector} and \tcode{deque}, @@ -1745,7 +1812,10 @@ from \tcode{*ranges::begin(rg)}. For \tcode{vector}, if \tcode{R} models -neither \tcode{ranges::\libconcept{sized_range}} nor \tcode{ranges::\libconcept{forward_range}}, +\tcode{ranges::\libconcept{approximately_sized_range}} +but not \tcode{ranges::\libconcept{sized_range}} or models +\tcode{ranges::\libconcept{input_range}} +but not \tcode{ranges::\libconcept{forward_range}}, \tcode{T} is also \oldconcept{MoveInsertable} into \tcode{X}. \tcode{rg} and \tcode{a} do not overlap. @@ -1757,6 +1827,12 @@ For \tcode{vector} and \tcode{deque}, also invalidates the past-the-end iterator. Each iterator in the range \tcode{rg} is dereferenced exactly once. + +\pnum +\recommended +If \tcode{R} models \tcode{ranges::\libconcept{approximately_sized_range}} and +\tcode{ranges::distance(\linebreak{}rg) <= ranges::reserve_hint(rg)} is \tcode{true}, +an implementation should not perform any reallocation. \end{itemdescr} \begin{itemdecl} @@ -1845,6 +1921,10 @@ \result \tcode{reference; const_reference} for constant \tcode{a}. +\pnum +\hardexpects +\tcode{a.empty()} is \tcode{false}. + \pnum \returns \tcode{*a.begin()} @@ -1856,6 +1936,7 @@ \tcode{array}, \tcode{deque}, \tcode{forward_list}, +\tcode{inplace_vector}, \tcode{list}, and \tcode{vector}. \end{itemdescr} @@ -1869,6 +1950,10 @@ \result \tcode{reference; const_reference} for constant \tcode{a}. +\pnum +\hardexpects +\tcode{a.empty()} is \tcode{false}. + \pnum \effects Equivalent to: @@ -1884,6 +1969,7 @@ \tcode{basic_string}, \tcode{array}, \tcode{deque}, +\tcode{inplace_vector}, \tcode{list}, and \tcode{vector}. \end{itemdescr} @@ -1946,6 +2032,7 @@ \remarks Required for \tcode{deque}, +\tcode{inplace_vector}, \tcode{list}, and \tcode{vector}. \end{itemdescr} @@ -2058,6 +2145,7 @@ Required for \tcode{basic_string}, \tcode{deque}, +\tcode{inplace_vector}, \tcode{list}, and \tcode{vector}. \end{itemdescr} @@ -2084,6 +2172,7 @@ Required for \tcode{basic_string}, \tcode{deque}, +\tcode{inplace_vector}, \tcode{list}, and \tcode{vector}. \end{itemdescr} @@ -2114,6 +2203,7 @@ \remarks Required for \tcode{deque}, +\tcode{inplace_vector}, \tcode{list}, and \tcode{vector}. \end{itemdescr} @@ -2128,7 +2218,7 @@ \keyword{void} \pnum -\expects +\hardexpects \tcode{a.empty()} is \tcode{false}. \pnum @@ -2153,7 +2243,7 @@ \keyword{void} \pnum -\expects +\hardexpects \tcode{a.empty()} is \tcode{false}. \pnum @@ -2165,6 +2255,7 @@ Required for \tcode{basic_string}, \tcode{deque}, +\tcode{inplace_vector}, \tcode{list}, and \tcode{vector}. \end{itemdescr} @@ -2176,7 +2267,11 @@ \begin{itemdescr} \pnum \result -\tcode{reference; const_reference} for constant \tcode{a} +\tcode{reference; const_reference} for constant \tcode{a}. + +\pnum +\hardexpects +\tcode{n < a.size()} is \tcode{true}. \pnum \effects @@ -2187,7 +2282,8 @@ Required for \tcode{basic_string}, \tcode{array}, -\tcode{deque}, and +\tcode{deque}, +\tcode{inplace_vector}, and \tcode{vector}. \end{itemdescr} @@ -2198,7 +2294,7 @@ \begin{itemdescr} \pnum \result -\tcode{reference; const_reference} for constant \tcode{a} +\tcode{reference; const_reference} for constant \tcode{a}. \pnum \returns @@ -2213,7 +2309,8 @@ Required for \tcode{basic_string}, \tcode{array}, -\tcode{deque}, and +\tcode{deque}, +\tcode{inplace_vector}, and \tcode{vector}. \end{itemdescr} @@ -2286,27 +2383,27 @@ public: // \ref{container.node.cons}, constructors, copy, and assignment constexpr @\placeholdernc{node-handle}@() noexcept : ptr_(), alloc_() {} - @\placeholdernc{node-handle}@(@\placeholdernc{node-handle}@&&) noexcept; - @\placeholdernc{node-handle}@& operator=(@\placeholdernc{node-handle}@&&); + constexpr @\placeholdernc{node-handle}@(@\placeholdernc{node-handle}@&&) noexcept; + constexpr @\placeholdernc{node-handle}@& operator=(@\placeholdernc{node-handle}@&&); // \ref{container.node.dtor}, destructor - ~@\placeholdernc{node-handle}@(); + constexpr ~@\placeholdernc{node-handle}@(); // \ref{container.node.observers}, observers - value_type& value() const; // not present for map containers - key_type& key() const; // not present for set containers - mapped_type& mapped() const; // not present for set containers + constexpr value_type& value() const; // not present for map containers + key_type& key() const; // not present for set containers + constexpr mapped_type& mapped() const; // not present for set containers - allocator_type get_allocator() const; - explicit operator bool() const noexcept; - [[nodiscard]] bool empty() const noexcept; + constexpr allocator_type get_allocator() const; + constexpr explicit operator bool() const noexcept; + constexpr bool empty() const noexcept; // \ref{container.node.modifiers}, modifiers - void swap(@\placeholdernc{node-handle}@&) + constexpr void swap(@\placeholdernc{node-handle}@&) noexcept(ator_traits::propagate_on_container_swap::value || ator_traits::is_always_equal::value); - friend void swap(@\placeholdernc{node-handle}@& x, @\placeholdernc{node-handle}@& y) noexcept(noexcept(x.swap(y))) { + constexpr friend void swap(@\placeholdernc{node-handle}@& x, @\placeholdernc{node-handle}@& y) noexcept(noexcept(x.swap(y))) { x.swap(y); } }; @@ -2315,7 +2412,7 @@ \rSec3[container.node.cons]{Constructors, copy, and assignment} \begin{itemdecl} -@\placeholdernc{node-handle}@(@\placeholdernc{node-handle}@&& nh) noexcept; +constexpr @\placeholdernc{node-handle}@(@\placeholdernc{node-handle}@&& nh) noexcept; \end{itemdecl} \begin{itemdescr} @@ -2328,7 +2425,7 @@ \end{itemdescr} \begin{itemdecl} -@\placeholdernc{node-handle}@& operator=(@\placeholdernc{node-handle}@&& nh); +constexpr @\placeholdernc{node-handle}@& operator=(@\placeholdernc{node-handle}@&& nh); \end{itemdecl} \begin{itemdescr} @@ -2370,7 +2467,7 @@ \rSec3[container.node.dtor]{Destructor} \begin{itemdecl} -~@\placeholdernc{node-handle}@(); +constexpr ~@\placeholdernc{node-handle}@(); \end{itemdecl} \begin{itemdescr} @@ -2385,7 +2482,7 @@ \rSec3[container.node.observers]{Observers} \begin{itemdecl} -value_type& value() const; +constexpr value_type& value() const; \end{itemdecl} \begin{itemdescr} @@ -2428,7 +2525,7 @@ \end{itemdescr} \begin{itemdecl} -mapped_type& mapped() const; +constexpr mapped_type& mapped() const; \end{itemdecl} \begin{itemdescr} @@ -2447,9 +2544,8 @@ Nothing. \end{itemdescr} - \begin{itemdecl} -allocator_type get_allocator() const; +constexpr allocator_type get_allocator() const; \end{itemdecl} \begin{itemdescr} @@ -2467,7 +2563,7 @@ \end{itemdescr} \begin{itemdecl} -explicit operator bool() const noexcept; +constexpr explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -2477,7 +2573,7 @@ \end{itemdescr} \begin{itemdecl} -[[nodiscard]] bool empty() const noexcept; +constexpr bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -2489,7 +2585,7 @@ \rSec3[container.node.modifiers]{Modifiers} \begin{itemdecl} -void swap(@\placeholdernc{node-handle}@& nh) +constexpr void swap(@\placeholdernc{node-handle}@& nh) noexcept(ator_traits::propagate_on_container_swap::value || ator_traits::is_always_equal::value); \end{itemdecl} @@ -2634,7 +2730,7 @@ \tcode{a2} denotes a value of a type with nodes compatible with type \tcode{X} (\tref{container.node.compat}), \item -\tcode{b} denotes a value or type \tcode{X} or \tcode{const X}, +\tcode{b} denotes a value of type \tcode{X} or \tcode{const X}, \item \tcode{u} denotes the name of a variable being declared, \item @@ -2665,7 +2761,7 @@ \item \tcode{r} denotes a valid dereferenceable iterator to \tcode{a}, \item -\tcode{[q1, q2)} denotes a valid range of constant iterators in \tcode{a}, +\range{q1}{q2} denotes a valid range of constant iterators in \tcode{a}, \item \tcode{il} designates an object of type \tcode{initializer_list}, \item @@ -2708,16 +2804,16 @@ \pnum A type \tcode{X} meets the \defnadj{associative}{container} requirements if \tcode{X} meets all the requirements of an allocator-aware -container\iref{container.reqmts} and +container\iref{container.alloc.reqmts} and the following types, statements, and expressions are well-formed and have the specified semantics, except that for \tcode{map} and \tcode{multimap}, the requirements placed on \tcode{value_type} -in \ref{container.alloc.reqmts} apply instead to \tcode{key_type} +in \ref{container.reqmts} apply instead to \tcode{key_type} and \tcode{mapped_type}. \begin{note} For example, in some cases \tcode{key_type} and \tcode{mapped_type} -are required to be \oldconcept{CopyAssignable} even though the associated +need to be \oldconcept{CopyAssignable} even though the associated \tcode{value_type}, \tcode{pair}, is not \oldconcept{CopyAssignable}. \end{note} @@ -2729,6 +2825,10 @@ \indexlibrary{\idxcode{map}!\idxcode{#1}}% \indexlibrary{\idxcode{multiset}!\idxcode{#1}}% \indexlibrary{\idxcode{multimap}!\idxcode{#1}}% +\indexlibrary{\idxcode{flat_set}!\idxcode{#1}}% +\indexlibrary{\idxcode{flat_map}!\idxcode{#1}}% +\indexlibrary{\idxcode{flat_multiset}!\idxcode{#1}}% +\indexlibrary{\idxcode{flat_multimap}!\idxcode{#1}}% } \indexordmem{key_type}% @@ -3506,7 +3606,7 @@ \pnum \expects -\tcode{a.get_allocator() == a2.get_allocator()}. +\tcode{a.get_allocator() == a2.get_allocator()} is \tcode{true}. \pnum \effects @@ -3521,7 +3621,8 @@ \ensures Pointers and references to the transferred elements of \tcode{a2} refer to those same elements but as members of \tcode{a}. -Iterators referring to the transferred elements +If \tcode{a.begin()} and \tcode{a2.begin()} have the same type, +iterators referring to the transferred elements will continue to refer to their elements, but they now behave as iterators into \tcode{a}, not into \tcode{a2}. @@ -3843,7 +3944,7 @@ \pnum \complexity -Logarithmic, +Logarithmic. \end{itemdescr} \indexordmem{upper_bound}% @@ -4150,7 +4251,7 @@ \tcode{i} and \tcode{j} denote input iterators that refer to \tcode{value_type}, \item -\tcode{[i, j)} denotes a valid range, +\range{i}{j} denotes a valid range, \item \tcode{rg} denotes a value of a type \tcode{R} that models \tcode{\exposconcept{container-compatible-range}}, @@ -4162,7 +4263,7 @@ \item \tcode{r} denotes a valid dereferenceable iterator to \tcode{a}, \item -\tcode{[q1, q2)} denotes a valid range in \tcode{a}, +\range{q1}{q2} denotes a valid range in \tcode{a}, \item \tcode{il} denotes a value of type \tcode{initializer_list}, \item @@ -4207,15 +4308,15 @@ A type \tcode{X} meets the \defnadj{unordered associative}{container} requirements if \tcode{X} meets all the requirements of -an allocator-aware container\iref{container.reqmts} and +an allocator-aware container\iref{container.alloc.reqmts} and the following types, statements, and expressions are well-formed and have the specified semantics, except that for \tcode{unordered_map} and \tcode{unordered_multimap}, -the requirements placed on \tcode{value_type} in \ref{container.alloc.reqmts} +the requirements placed on \tcode{value_type} in \ref{container.reqmts} apply instead to \tcode{key_type} and \tcode{mapped_type}. \begin{note} For example, \tcode{key_type} and \tcode{mapped_type} -are sometimes required to be \oldconcept{CopyAssignable} +sometimes need to be \oldconcept{CopyAssignable} even though the associated \tcode{value_type}, \tcode{pair}, is not \oldconcept{CopyAssignable}. @@ -4974,7 +5075,7 @@ \pnum \effects -Equivalent to \tcode{a.insert(t)} for each element in \tcode{[i,j)}. +Equivalent to \tcode{a.insert(t)} for each element in \range{i}{j}. \pnum \complexity @@ -5337,7 +5438,7 @@ \pnum \effects -Erases all elements in the range \tcode{[q1, q2)}. +Erases all elements in the range \range{q1}{q2}. \pnum \returns @@ -5573,7 +5674,7 @@ The index of the bucket in which elements with keys equivalent to \tcode{k} would be found, if any such element existed. -The return value is in the range \tcode{[0, b.bucket_count())}. +The return value is in the range \range{0}{b.bucket_count()}. \pnum \complexity @@ -5596,7 +5697,7 @@ \pnum \ensures -The return value is in the range \tcode{[0, a_tran.bucket_count())}. +The return value is in the range \range{0}{a_tran.bucket_count()}. \pnum \returns @@ -5621,7 +5722,7 @@ \pnum \expects -\tcode{n} shall be in the range \tcode{[0, b.bucket_count())}. +\tcode{n} shall be in the range \range{0}{b.bucket_count()}. \pnum \returns @@ -5644,7 +5745,7 @@ \pnum \expects -\tcode{n} is in the range \tcode{[0, b.bucket_count())}. +\tcode{n} is in the range \range{0}{b.bucket_count()}. \pnum \returns @@ -5668,7 +5769,7 @@ \pnum \expects -\tcode{n} is in the range \tcode{[0, b.bucket_count())}. +\tcode{n} is in the range \range{0}{b.bucket_count()}. \pnum \returns @@ -5691,7 +5792,7 @@ \pnum \expects -\tcode{n} shall be in the range \tcode{[0, b.bucket_count())}. +\tcode{n} shall be in the range \range{0}{b.bucket_count()}. \pnum \returns @@ -5715,7 +5816,7 @@ \pnum \expects -\tcode{n} is in the range \tcode{[0, b.bucket_count())}. +\tcode{n} is in the range \range{0}{b.bucket_count()}. \pnum \returns @@ -5874,7 +5975,7 @@ \indextext{unordered associative containers!requirements}% The \tcode{insert}, \tcode{insert_range}, and \tcode{emplace} members shall not affect the validity of iterators if -\tcode{(N+n) <= z * B}, where \tcode{N} is the number of elements in +\tcode{(N + n) <= z * B}, where \tcode{N} is the number of elements in the container prior to the insert operation, \tcode{n} is the number of elements inserted, \tcode{B} is the container's bucket count, and \tcode{z} is the container's maximum load factor. @@ -5950,13 +6051,15 @@ \rSec1[sequences]{Sequence containers} -\rSec2[sequences.general]{In general} +\rSec2[sequences.general]{General} \pnum The headers \libheaderref{array}, \libheaderref{deque}, \libheaderrefx{forward_list}{forward.list.syn}, +\libheaderref{hive}, +\libheaderrefx{inplace_vector}{inplace.vector.syn}, \libheaderref{list}, and \libheaderref{vector} define class templates that meet the requirements for sequence containers. @@ -5973,12 +6076,13 @@ \indexheader{array}% \begin{codeblock} +// mostly freestanding #include // see \ref{compare.syn} #include // see \ref{initializer.list.syn} namespace std { // \ref{array}, class template \tcode{array} - template struct array; + template struct array; // partially freestanding template constexpr bool operator==(const array& x, const array& y); @@ -6014,166 +6118,6 @@ } \end{codeblock} -\rSec2[deque.syn]{Header \tcode{} synopsis} - -\indexheader{deque}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} - -namespace std { - // \ref{deque}, class template \tcode{deque} - template> class deque; - - template - bool operator==(const deque& x, const deque& y); - template - @\placeholder{synth-three-way-result}@ operator<=>(const deque& x, - @\itcorr@ const deque& y); - - template - void swap(deque& x, deque& y) - noexcept(noexcept(x.swap(y))); - - // \ref{deque.erasure}, erasure - template - typename deque::size_type - erase(deque& c, const U& value); - template - typename deque::size_type - erase_if(deque& c, Predicate pred); - - namespace pmr { - template - using deque = std::deque>; - } -} -\end{codeblock} - -\rSec2[forward.list.syn]{Header \tcode{} synopsis} - -\indexheader{forward_list}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} - -namespace std { - // \ref{forward.list}, class template \tcode{forward_list} - template> class forward_list; - - template - bool operator==(const forward_list& x, const forward_list& y); - template - @\placeholder{synth-three-way-result}@ operator<=>(const forward_list& x, - @\itcorr@ const forward_list& y); - - template - void swap(forward_list& x, forward_list& y) - noexcept(noexcept(x.swap(y))); - - // \ref{forward.list.erasure}, erasure - template - typename forward_list::size_type - erase(forward_list& c, const U& value); - template - typename forward_list::size_type - erase_if(forward_list& c, Predicate pred); - - namespace pmr { - template - using forward_list = std::forward_list>; - } -} -\end{codeblock} - -\rSec2[list.syn]{Header \tcode{} synopsis} - -\indexheader{list}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} - -namespace std { - // \ref{list}, class template \tcode{list} - template> class list; - - template - bool operator==(const list& x, const list& y); - template - @\placeholder{synth-three-way-result}@ operator<=>(const list& x, - @\itcorr@ const list& y); - - template - void swap(list& x, list& y) - noexcept(noexcept(x.swap(y))); - - // \ref{list.erasure}, erasure - template - typename list::size_type - erase(list& c, const U& value); - template - typename list::size_type - erase_if(list& c, Predicate pred); - - namespace pmr { - template - using list = std::list>; - } -} -\end{codeblock} - -\rSec2[vector.syn]{Header \tcode{} synopsis} - -\indexheader{vector}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} - -namespace std { - // \ref{vector}, class template \tcode{vector} - template> class vector; - - template - constexpr bool operator==(const vector& x, const vector& y); - template - constexpr @\placeholder{synth-three-way-result}@ operator<=>(const vector& x, - @\itcorr@ const vector& y); - - template - constexpr void swap(vector& x, vector& y) - noexcept(noexcept(x.swap(y))); - - // \ref{vector.erasure}, erasure - template - constexpr typename vector::size_type - erase(vector& c, const U& value); - template - constexpr typename vector::size_type - erase_if(vector& c, Predicate pred); - - namespace pmr { - template - using vector = std::vector>; - } - - // \ref{vector.bool}, specialization of \tcode{vector} for \tcode{bool} - // \ref{vector.bool.pspc}, partial class template specialization \tcode{vector} - template - class vector; - - template - constexpr bool @\exposid{is-vector-bool-reference}@ = @\seebelow@; // \expos - - // hash support - template struct hash; - template struct hash>; - - // \ref{vector.bool.fmt}, formatter specialization for \tcode{vector} - template requires @\exposid{is-vector-bool-reference}@ - struct formatter; -} -\end{codeblock} - \rSec2[array]{Class template \tcode{array}} \indexlibraryglobal{array}% @@ -6264,22 +6208,22 @@ constexpr const_reverse_iterator crend() const noexcept; // capacity - [[nodiscard]] constexpr bool empty() const noexcept; + constexpr bool empty() const noexcept; constexpr size_type size() const noexcept; constexpr size_type max_size() const noexcept; // element access constexpr reference operator[](size_type n); constexpr const_reference operator[](size_type n) const; - constexpr reference at(size_type n); - constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); // freestanding-deleted + constexpr const_reference at(size_type n) const; // freestanding-deleted constexpr reference front(); constexpr const_reference front() const; constexpr reference back(); constexpr const_reference back() const; - constexpr T * data() noexcept; - constexpr const T * data() const noexcept; + constexpr T* data() noexcept; + constexpr const T* data() const noexcept; }; template @@ -6292,12 +6236,11 @@ \pnum \indextext{\idxcode{array}!initialization}% \indextext{requirements!container}% -The conditions for an aggregate\iref{dcl.init.aggr} shall be -met. Class \tcode{array} relies on the implicitly-declared special +An \tcode{array} relies on the implicitly-declared special member functions\iref{class.default.ctor,class.dtor,class.copy.ctor} to conform to the container requirements table in~\ref{container.requirements}. In addition to the requirements specified in the container requirements table, -the implicit move constructor and move assignment operator for \tcode{array} +the implicitly-declared move constructor and move assignment operator for \tcode{array} require that \tcode{T} be \oldconcept{MoveConstructible} or \oldconcept{MoveAssignable}, respectively. @@ -6419,7 +6362,7 @@ \pnum \mandates \tcode{is_array_v} is \tcode{false} and -\tcode{is_constructible_v} is \tcode{true}. +\tcode{is_constructible_v, T\&>} is \tcode{true}. \pnum \expects @@ -6440,7 +6383,7 @@ \pnum \mandates \tcode{is_array_v} is \tcode{false} and -\tcode{is_move_constructible_v} is \tcode{true}. +\tcode{is_constructible_v, T>} is \tcode{true}. \pnum \expects @@ -6498,6 +6441,42 @@ where indexing is zero-based. \end{itemdescr} +\rSec2[deque.syn]{Header \tcode{} synopsis} + +\indexheader{deque}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{deque}, class template \tcode{deque} + template> class deque; + + template + constexpr bool operator==(const deque& x, const deque& y); + template + constexpr @\placeholder{synth-three-way-result}@ operator<=>(const deque& x, + @\itcorr@ const deque& y); + + template + constexpr void swap(deque& x, deque& y) + noexcept(noexcept(x.swap(y))); + + // \ref{deque.erasure}, erasure + template + constexpr typename deque::size_type + erase(deque& c, const U& value); + template + constexpr typename deque::size_type + erase_if(deque& c, Predicate pred); + + namespace pmr { + template + using deque = std::deque>; + } +} +\end{codeblock} + \rSec2[deque]{Class template \tcode{deque}} \rSec3[deque.overview]{Overview} @@ -6524,6 +6503,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> @@ -6544,97 +6527,98 @@ using const_reverse_iterator = std::reverse_iterator; // \ref{deque.cons}, construct/copy/destroy - deque() : deque(Allocator()) { } - explicit deque(const Allocator&); - explicit deque(size_type n, const Allocator& = Allocator()); - deque(size_type n, const T& value, const Allocator& = Allocator()); + constexpr deque() : deque(Allocator()) { } + constexpr explicit deque(const Allocator&); + constexpr explicit deque(size_type n, const Allocator& = Allocator()); + constexpr deque(size_type n, const T& value, const Allocator& = Allocator()); template - deque(InputIterator first, InputIterator last, const Allocator& = Allocator()); + constexpr deque(InputIterator first, InputIterator last, const Allocator& = Allocator()); template<@\exposconcept{container-compatible-range}@ R> - deque(from_range_t, R&& rg, const Allocator& = Allocator()); - deque(const deque& x); - deque(deque&&); - deque(const deque&, const type_identity_t&); - deque(deque&&, const type_identity_t&); - deque(initializer_list, const Allocator& = Allocator()); - - ~deque(); - deque& operator=(const deque& x); - deque& operator=(deque&& x) + constexpr deque(from_range_t, R&& rg, const Allocator& = Allocator()); + constexpr deque(const deque& x); + constexpr deque(deque&&); + constexpr deque(const deque&, const type_identity_t&); + constexpr deque(deque&&, const type_identity_t&); + constexpr deque(initializer_list, const Allocator& = Allocator()); + + constexpr ~deque(); + constexpr deque& operator=(const deque& x); + constexpr deque& operator=(deque&& x) noexcept(allocator_traits::is_always_equal::value); - deque& operator=(initializer_list); + constexpr deque& operator=(initializer_list); template - void assign(InputIterator first, InputIterator last); + constexpr void assign(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void assign_range(R&& rg); - void assign(size_type n, const T& t); - void assign(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr void assign_range(R&& rg); + constexpr void assign(size_type n, const T& 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; - - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() 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; + + 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{deque.capacity}, capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; - void resize(size_type sz); - void resize(size_type sz, const T& c); - void shrink_to_fit(); + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + constexpr void resize(size_type sz); + constexpr void resize(size_type sz, const T& c); + constexpr void shrink_to_fit(); // element access - reference operator[](size_type n); - const_reference operator[](size_type n) const; - reference at(size_type n); - const_reference at(size_type n) const; - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - // \ref{deque.modifiers}, modifiers - template reference emplace_front(Args&&... args); - template reference emplace_back(Args&&... args); - template iterator emplace(const_iterator position, Args&&... args); - - void push_front(const T& x); - void push_front(T&& x); - template<@\exposconcept{container-compatible-range}@ R> - void prepend_range(R&& rg); - void push_back(const T& x); - void push_back(T&& x); - template<@\exposconcept{container-compatible-range}@ R> - void append_range(R&& rg); - - 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 reference operator[](size_type n); + constexpr const_reference operator[](size_type n) const; + constexpr reference at(size_type n); + constexpr const_reference at(size_type n) const; + constexpr reference front(); + constexpr const_reference front() const; + constexpr reference back(); + constexpr const_reference back() const; + + // \ref{deque.modifiers}, modifiers + template constexpr reference emplace_front(Args&&... args); + template constexpr reference emplace_back(Args&&... args); + template constexpr iterator emplace(const_iterator position, Args&&... args); + + constexpr void push_front(const T& x); + constexpr void push_front(T&& x); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void prepend_range(R&& rg); + constexpr void push_back(const T& x); + constexpr void push_back(T&& x); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void append_range(R&& rg); + + 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); + constexpr iterator insert(const_iterator position, + InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - iterator insert_range(const_iterator position, R&& rg); - iterator insert(const_iterator position, initializer_list); + constexpr iterator insert_range(const_iterator position, R&& rg); + constexpr iterator insert(const_iterator position, initializer_list); - void pop_front(); - void pop_back(); + constexpr void pop_front(); + constexpr void pop_back(); - iterator erase(const_iterator position); - iterator erase(const_iterator first, const_iterator last); - void swap(deque&) + constexpr iterator erase(const_iterator position); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(deque&) noexcept(allocator_traits::is_always_equal::value); - void clear() noexcept; + constexpr void clear() noexcept; }; template>> @@ -6651,7 +6635,7 @@ \indexlibraryctor{deque}% \begin{itemdecl} -explicit deque(const Allocator&); +constexpr explicit deque(const Allocator&); \end{itemdecl} \begin{itemdescr} @@ -6668,13 +6652,13 @@ \indexlibraryctor{deque}% \begin{itemdecl} -explicit deque(size_type n, const Allocator& = Allocator()); +constexpr explicit deque(size_type n, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{deque}. \pnum \effects @@ -6688,13 +6672,13 @@ \indexlibraryctor{deque}% \begin{itemdecl} -deque(size_type n, const T& value, const Allocator& = Allocator()); +constexpr deque(size_type n, const T& value, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{CopyInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{deque}. \pnum \effects @@ -6711,7 +6695,7 @@ \indexlibraryctor{deque}% \begin{itemdecl} template - deque(InputIterator first, InputIterator last, const Allocator& = Allocator()); + constexpr deque(InputIterator first, InputIterator last, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -6731,7 +6715,7 @@ \indexlibraryctor{deque}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - deque(from_range_t, R&& rg, const Allocator& = Allocator()); + constexpr deque(from_range_t, R&& rg, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -6749,13 +6733,13 @@ \indexlibrarymember{resize}{deque}% \begin{itemdecl} -void resize(size_type sz); +constexpr void resize(size_type sz); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{MoveInsertable} and \oldconcept{DefaultInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{MoveInsertable} and \oldconcept{DefaultInsertable} into \tcode{deque}. \pnum \effects @@ -6766,13 +6750,13 @@ \indexlibrarymember{resize}{deque}% \begin{itemdecl} -void resize(size_type sz, const T& c); +constexpr void resize(size_type sz, const T& c); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{CopyInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{deque}. \pnum \effects @@ -6783,13 +6767,13 @@ \indexlibrarymember{shrink_to_fit}{deque}% \begin{itemdecl} -void shrink_to_fit(); +constexpr void shrink_to_fit(); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{MoveInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{MoveInsertable} into \tcode{deque}. \pnum \effects @@ -6825,27 +6809,27 @@ \indexlibrarymember{push_back}{deque}% \indexlibrarymember{emplace}{deque}% \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); + constexpr iterator insert(const_iterator position, + InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - iterator insert_range(const_iterator position, R&& rg); -iterator insert(const_iterator position, initializer_list); - -template reference emplace_front(Args&&... args); -template reference emplace_back(Args&&... args); -template iterator emplace(const_iterator position, Args&&... args); -void push_front(const T& x); -void push_front(T&& x); + constexpr iterator insert_range(const_iterator position, R&& rg); +constexpr iterator insert(const_iterator position, initializer_list); + +template constexpr reference emplace_front(Args&&... args); +template constexpr reference emplace_back(Args&&... args); +template constexpr iterator emplace(const_iterator position, Args&&... args); +constexpr void push_front(const T& x); +constexpr void push_front(T&& x); template<@\exposconcept{container-compatible-range}@ R> - void prepend_range(R&& rg); -void push_back(const T& x); -void push_back(T&& x); + constexpr void prepend_range(R&& rg); +constexpr void push_back(const T& x); +constexpr void push_back(T&& x); template<@\exposconcept{container-compatible-range}@ R> - void append_range(R&& rg); + constexpr void append_range(R&& rg); \end{itemdecl} \begin{itemdescr} @@ -6870,7 +6854,7 @@ If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of -\tcode{T} +\tcode{T}, there are no effects. If an exception is thrown while inserting a single element at either end, there are no effects. @@ -6881,10 +6865,10 @@ \indexlibrarymember{erase}{deque}% \begin{itemdecl} -iterator erase(const_iterator position); -iterator erase(const_iterator first, const_iterator last); -void pop_front(); -void pop_back(); +constexpr iterator erase(const_iterator position); +constexpr iterator erase(const_iterator first, const_iterator last); +constexpr void pop_front(); +constexpr void pop_back(); \end{itemdecl} \begin{itemdescr} @@ -6916,8 +6900,8 @@ \indexlibrarymember{erase}{deque}% \begin{itemdecl} -template - typename deque::size_type +template + constexpr typename deque::size_type erase(deque& c, const U& value); \end{itemdecl} @@ -6936,7 +6920,7 @@ \indexlibrarymember{erase_if}{deque}% \begin{itemdecl} template - typename deque::size_type + constexpr typename deque::size_type erase_if(deque& c, Predicate pred); \end{itemdecl} @@ -6952,6 +6936,43 @@ \end{codeblock} \end{itemdescr} +\rSec2[forward.list.syn]{Header \tcode{} synopsis} + +\indexheader{forward_list}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{forward.list}, class template \tcode{forward_list} + template> class forward_list; + + template + constexpr bool operator==(const forward_list& x, + const forward_list& y); + template + constexpr @\placeholder{synth-three-way-result}@ operator<=>(const forward_list& x, + @\itcorr@ const forward_list& y); + + template + constexpr void swap(forward_list& x, forward_list& y) + noexcept(noexcept(x.swap(y))); + + // \ref{forward.list.erasure}, erasure + template + constexpr typename forward_list::size_type + erase(forward_list& c, const U& value); + template + constexpr typename forward_list::size_type + erase_if(forward_list& c, Predicate pred); + + namespace pmr { + template + using forward_list = std::forward_list>; + } +} +\end{codeblock} + \rSec2[forward.list]{Class template \tcode{forward_list}} \rSec3[forward.list.overview]{Overview} @@ -6970,7 +6991,7 @@ A \tcode{forward_list} meets all of the requirements of a container\iref{container.reqmts}, except that the \tcode{size()} member function is not provided and -\tcode{operator==} has linear complexity, +\tcode{operator==} has linear complexity. A \tcode{forward_list} also meets all of the requirements for an allocator-aware container\iref{container.alloc.reqmts}. In addition, a \tcode{forward_list} @@ -6989,6 +7010,10 @@ take fully-open ranges, not semi-open ranges. \end{note} +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. + \begin{codeblock} namespace std { template> @@ -7007,105 +7032,108 @@ using const_iterator = @\impdefx{type of \tcode{forward_list::const_iterator}}@; // see \ref{container.requirements} // \ref{forward.list.cons}, construct/copy/destroy - forward_list() : forward_list(Allocator()) { } - explicit forward_list(const Allocator&); - explicit forward_list(size_type n, const Allocator& = Allocator()); - forward_list(size_type n, const T& value, const Allocator& = Allocator()); + constexpr forward_list() : forward_list(Allocator()) { } + constexpr explicit forward_list(const Allocator&); + constexpr explicit forward_list(size_type n, const Allocator& = Allocator()); + constexpr forward_list(size_type n, const T& value, const Allocator& = Allocator()); template - forward_list(InputIterator first, InputIterator last, const Allocator& = Allocator()); + constexpr forward_list(InputIterator first, InputIterator last, + const Allocator& = Allocator()); template<@\exposconcept{container-compatible-range}@ R> - forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); - forward_list(const forward_list& x); - forward_list(forward_list&& x); - forward_list(const forward_list& x, const type_identity_t&); - forward_list(forward_list&& x, const type_identity_t&); - forward_list(initializer_list, const Allocator& = Allocator()); - ~forward_list(); - forward_list& operator=(const forward_list& x); - forward_list& operator=(forward_list&& x) + constexpr forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); + constexpr forward_list(const forward_list& x); + constexpr forward_list(forward_list&& x); + constexpr forward_list(const forward_list& x, const type_identity_t&); + constexpr forward_list(forward_list&& x, const type_identity_t&); + constexpr forward_list(initializer_list, const Allocator& = Allocator()); + constexpr ~forward_list(); + constexpr forward_list& operator=(const forward_list& x); + constexpr forward_list& operator=(forward_list&& x) noexcept(allocator_traits::is_always_equal::value); - forward_list& operator=(initializer_list); + constexpr forward_list& operator=(initializer_list); template - void assign(InputIterator first, InputIterator last); + constexpr void assign(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void assign_range(R&& rg); - void assign(size_type n, const T& t); - void assign(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr void assign_range(R&& rg); + constexpr void assign(size_type n, const T& t); + constexpr void assign(initializer_list); + constexpr allocator_type get_allocator() const noexcept; // \ref{forward.list.iter}, iterators - iterator before_begin() noexcept; - const_iterator before_begin() const noexcept; - iterator begin() noexcept; - const_iterator begin() const noexcept; - iterator end() noexcept; - const_iterator end() const noexcept; + constexpr iterator before_begin() noexcept; + constexpr const_iterator before_begin() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; - const_iterator cbegin() const noexcept; - const_iterator cbefore_begin() const noexcept; - const_iterator cend() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cbefore_begin() const noexcept; + constexpr const_iterator cend() const noexcept; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type max_size() const noexcept; // \ref{forward.list.access}, element access - reference front(); - const_reference front() const; + constexpr reference front(); + constexpr const_reference front() const; // \ref{forward.list.modifiers}, modifiers - template reference emplace_front(Args&&... args); - void push_front(const T& x); - void push_front(T&& x); + template constexpr reference emplace_front(Args&&... args); + constexpr void push_front(const T& x); + constexpr void push_front(T&& x); template<@\exposconcept{container-compatible-range}@ R> - void prepend_range(R&& rg); - void pop_front(); + constexpr void prepend_range(R&& rg); + constexpr void pop_front(); - template iterator emplace_after(const_iterator position, Args&&... args); - iterator insert_after(const_iterator position, const T& x); - iterator insert_after(const_iterator position, T&& x); + template + constexpr iterator emplace_after(const_iterator position, Args&&... args); + constexpr iterator insert_after(const_iterator position, const T& x); + constexpr iterator insert_after(const_iterator position, T&& x); - iterator insert_after(const_iterator position, size_type n, const T& x); + constexpr iterator insert_after(const_iterator position, size_type n, const T& x); template - iterator insert_after(const_iterator position, InputIterator first, InputIterator last); - iterator insert_after(const_iterator position, initializer_list il); + constexpr iterator insert_after(const_iterator position, + InputIterator first, InputIterator last); + constexpr iterator insert_after(const_iterator position, initializer_list il); template<@\exposconcept{container-compatible-range}@ R> - iterator insert_range_after(const_iterator position, R&& rg); + constexpr iterator insert_range_after(const_iterator position, R&& rg); - iterator erase_after(const_iterator position); - iterator erase_after(const_iterator position, const_iterator last); - void swap(forward_list&) + constexpr iterator erase_after(const_iterator position); + constexpr iterator erase_after(const_iterator position, const_iterator last); + constexpr void swap(forward_list&) noexcept(allocator_traits::is_always_equal::value); - void resize(size_type sz); - void resize(size_type sz, const value_type& c); - void clear() noexcept; + constexpr void resize(size_type sz); + constexpr void resize(size_type sz, const value_type& c); + constexpr void clear() noexcept; // \ref{forward.list.ops}, \tcode{forward_list} operations - void splice_after(const_iterator position, forward_list& x); - void splice_after(const_iterator position, forward_list&& x); - void splice_after(const_iterator position, forward_list& x, const_iterator i); - void splice_after(const_iterator position, forward_list&& x, const_iterator i); - void splice_after(const_iterator position, forward_list& x, + constexpr void splice_after(const_iterator position, forward_list& x); + constexpr void splice_after(const_iterator position, forward_list&& x); + constexpr void splice_after(const_iterator position, forward_list& x, const_iterator i); + constexpr void splice_after(const_iterator position, forward_list&& x, const_iterator i); + constexpr void splice_after(const_iterator position, forward_list& x, const_iterator first, const_iterator last); - void splice_after(const_iterator position, forward_list&& x, + constexpr void splice_after(const_iterator position, forward_list&& x, const_iterator first, const_iterator last); - size_type remove(const T& value); - template size_type remove_if(Predicate pred); + constexpr size_type remove(const T& value); + template constexpr size_type remove_if(Predicate pred); size_type unique(); - template size_type unique(BinaryPredicate binary_pred); + template constexpr size_type unique(BinaryPredicate binary_pred); - void merge(forward_list& x); - void merge(forward_list&& x); - template void merge(forward_list& x, Compare comp); - template void merge(forward_list&& x, Compare comp); + constexpr void merge(forward_list& x); + constexpr void merge(forward_list&& x); + template constexpr void merge(forward_list& x, Compare comp); + template constexpr void merge(forward_list&& x, Compare comp); - void sort(); - template void sort(Compare comp); + constexpr void sort(); + template constexpr void sort(Compare comp); - void reverse() noexcept; + constexpr void reverse() noexcept; }; template>> @@ -7129,7 +7157,7 @@ \indexlibraryctor{forward_list}% \begin{itemdecl} -explicit forward_list(const Allocator&); +constexpr explicit forward_list(const Allocator&); \end{itemdecl} \begin{itemdescr} @@ -7144,13 +7172,13 @@ \indexlibraryctor{forward_list}% \begin{itemdecl} -explicit forward_list(size_type n, const Allocator& = Allocator()); +constexpr explicit forward_list(size_type n, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{forward_list}. \pnum \effects @@ -7164,13 +7192,13 @@ \indexlibraryctor{forward_list}% \begin{itemdecl} -forward_list(size_type n, const T& value, const Allocator& = Allocator()); +constexpr forward_list(size_type n, const T& value, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{CopyInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{forward_list}. \pnum \effects @@ -7184,7 +7212,7 @@ \indexlibraryctor{forward_list}% \begin{itemdecl} template - forward_list(InputIterator first, InputIterator last, const Allocator& = Allocator()); + constexpr forward_list(InputIterator first, InputIterator last, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -7200,7 +7228,7 @@ \indexlibraryctor{forward_list}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); + constexpr forward_list(from_range_t, R&& rg, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -7219,9 +7247,9 @@ \indexlibrarymember{before_begin}{forward_list}% \indexlibrarymember{cbefore_begin}{forward_list}% \begin{itemdecl} -iterator before_begin() noexcept; -const_iterator before_begin() const noexcept; -const_iterator cbefore_begin() const noexcept; +constexpr iterator before_begin() noexcept; +constexpr const_iterator before_begin() const noexcept; +constexpr const_iterator cbefore_begin() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -7244,8 +7272,8 @@ \indexlibrarymember{front}{forward_list}% \begin{itemdecl} -reference front(); -const_reference front() const; +constexpr reference front(); +constexpr const_reference front() const; \end{itemdecl} \begin{itemdescr} @@ -7257,10 +7285,13 @@ \rSec3[forward.list.modifiers]{Modifiers} \pnum -None of the overloads of \tcode{insert_after} shall affect the validity of iterators and -references, and \tcode{erase_after} shall invalidate only iterators and references to -the erased elements. If an exception is thrown during \tcode{insert_after} there shall -be no effect. Inserting \tcode{n} elements into a \tcode{forward_list} is linear in +The member functions in this subclause +do not affect the validity of iterators and references +when inserting elements, and when erasing elements +invalidate iterators and references to the erased elements only. +If an exception is thrown by any of these member functions +there is no effect on the container. +Inserting \tcode{n} elements into a \tcode{forward_list} is linear in \tcode{n}, and the number of calls to the copy or move constructor of \tcode{T} is exactly equal to \tcode{n}. Erasing \tcode{n} elements from a \tcode{forward_list} is linear in \tcode{n} and the number of calls to the destructor of type \tcode{T} is @@ -7268,7 +7299,7 @@ \indexlibrarymember{emplace_front}{forward_list}% \begin{itemdecl} -template reference emplace_front(Args&&... args); +template constexpr reference emplace_front(Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -7280,8 +7311,8 @@ \indexlibrarymember{push_front}{forward_list}% \begin{itemdecl} -void push_front(const T& x); -void push_front(T&& x); +constexpr void push_front(const T& x); +constexpr void push_front(T&& x); \end{itemdecl} \begin{itemdescr} @@ -7293,7 +7324,7 @@ \indexlibrarymember{prepend_range}{forward_list}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - void prepend_range(R&& rg); + constexpr void prepend_range(R&& rg); \end{itemdecl} \begin{itemdescr} @@ -7307,7 +7338,7 @@ \indexlibrarymember{pop}{forward_list}% \begin{itemdecl} -void pop_front(); +constexpr void pop_front(); \end{itemdecl} \begin{itemdescr} @@ -7318,7 +7349,7 @@ \indexlibrarymember{insert_after}{forward_list}% \begin{itemdecl} -iterator insert_after(const_iterator position, const T& x); +constexpr iterator insert_after(const_iterator position, const T& x); \end{itemdecl} \begin{itemdescr} @@ -7339,7 +7370,7 @@ \indexlibrarymember{insert_after}{forward_list}% \begin{itemdecl} -iterator insert_after(const_iterator position, T&& x); +constexpr iterator insert_after(const_iterator position, T&& x); \end{itemdecl} \begin{itemdescr} @@ -7360,7 +7391,7 @@ \indexlibrarymember{insert_after}{forward_list}% \begin{itemdecl} -iterator insert_after(const_iterator position, size_type n, const T& x); +constexpr iterator insert_after(const_iterator position, size_type n, const T& x); \end{itemdecl} \begin{itemdescr} @@ -7383,7 +7414,8 @@ \indexlibrarymember{insert_after}{forward_list}% \begin{itemdecl} template - iterator insert_after(const_iterator position, InputIterator first, InputIterator last); + constexpr iterator insert_after(const_iterator position, + InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} @@ -7408,7 +7440,7 @@ \indexlibrarymember{insert_range_after}{forward_list}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - iterator insert_range_after(const_iterator position, R&& rg); + constexpr iterator insert_range_after(const_iterator position, R&& rg); \end{itemdecl} \begin{itemdescr} @@ -7432,7 +7464,7 @@ \indexlibrarymember{insert_after}{forward_list}% \begin{itemdecl} -iterator insert_after(const_iterator position, initializer_list il); +constexpr iterator insert_after(const_iterator position, initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -7445,7 +7477,7 @@ \indexlibrarymember{emplace_after}{forward_list}% \begin{itemdecl} template - iterator emplace_after(const_iterator position, Args&&... args); + constexpr iterator emplace_after(const_iterator position, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -7468,7 +7500,7 @@ \indexlibrarymember{erase_after}{forward_list}% \begin{itemdecl} -iterator erase_after(const_iterator position); +constexpr iterator erase_after(const_iterator position); \end{itemdecl} \begin{itemdescr} @@ -7491,7 +7523,7 @@ \end{itemdescr} \begin{itemdecl} -iterator erase_after(const_iterator position, const_iterator last); +constexpr iterator erase_after(const_iterator position, const_iterator last); \end{itemdecl} \begin{itemdescr} @@ -7514,13 +7546,13 @@ \indexlibrarymember{resize}{forward_list}% \begin{itemdecl} -void resize(size_type sz); +constexpr void resize(size_type sz); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{forward_list}. \pnum \effects @@ -7530,13 +7562,13 @@ \end{itemdescr} \begin{itemdecl} -void resize(size_type sz, const value_type& c); +constexpr void resize(size_type sz, const value_type& c); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{CopyInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{forward_list}. \pnum \effects @@ -7548,7 +7580,7 @@ \indexlibrarymember{clear}{forward_list}% \begin{itemdecl} -void clear() noexcept; +constexpr void clear() noexcept; \end{itemdecl} \begin{itemdescr} @@ -7579,8 +7611,8 @@ \indexlibrarymember{splice_after}{forward_list}% \begin{itemdecl} -void splice_after(const_iterator position, forward_list& x); -void splice_after(const_iterator position, forward_list&& x); +constexpr void splice_after(const_iterator position, forward_list& x); +constexpr void splice_after(const_iterator position, forward_list&& x); \end{itemdecl} \begin{itemdescr} @@ -7610,8 +7642,8 @@ \indexlibrarymember{splice_after}{forward_list}% \begin{itemdecl} -void splice_after(const_iterator position, forward_list& x, const_iterator i); -void splice_after(const_iterator position, forward_list&& x, const_iterator i); +constexpr void splice_after(const_iterator position, forward_list& x, const_iterator i); +constexpr void splice_after(const_iterator position, forward_list&& x, const_iterator i); \end{itemdecl} \begin{itemdescr} @@ -7642,10 +7674,10 @@ \indexlibrarymember{splice_after}{forward_list}% \begin{itemdecl} -void splice_after(const_iterator position, forward_list& x, - const_iterator first, const_iterator last); -void splice_after(const_iterator position, forward_list&& x, - const_iterator first, const_iterator last); +constexpr void splice_after(const_iterator position, forward_list& x, + const_iterator first, const_iterator last); +constexpr void splice_after(const_iterator position, forward_list&& x, + const_iterator first, const_iterator last); \end{itemdecl} \begin{itemdescr} @@ -7673,8 +7705,8 @@ \indexlibrarymember{remove}{forward_list}% \indexlibrarymember{remove_if}{forward_list}% \begin{itemdecl} -size_type remove(const T& value); -template size_type remove_if(Predicate pred); +constexpr size_type remove(const T& value); +template constexpr size_type remove_if(Predicate pred); \end{itemdecl} \begin{itemdescr} @@ -7706,8 +7738,8 @@ \indexlibrarymember{unique}{forward_list}% \begin{itemdecl} -size_type unique(); -template size_type unique(BinaryPredicate binary_pred); +constexpr size_type unique(); +template constexpr size_type unique(BinaryPredicate binary_pred); \end{itemdecl} \begin{itemdescr} @@ -7745,10 +7777,10 @@ \indexlibrarymember{merge}{forward_list}% \begin{itemdecl} -void merge(forward_list& x); -void merge(forward_list&& x); -template void merge(forward_list& x, Compare comp); -template void merge(forward_list&& x, Compare comp); +constexpr void merge(forward_list& x); +constexpr void merge(forward_list&& x); +template constexpr void merge(forward_list& x, Compare comp); +template constexpr void merge(forward_list&& x, Compare comp); \end{itemdecl} \begin{itemdescr} @@ -7789,8 +7821,8 @@ \indexlibrarymember{sort}{forward_list}% \begin{itemdecl} -void sort(); -template void sort(Compare comp); +constexpr void sort(); +template constexpr void sort(Compare comp); \end{itemdecl} \begin{itemdescr} @@ -7811,7 +7843,7 @@ \indexlibrarymember{reverse}{forward_list}% \begin{itemdecl} -void reverse() noexcept; +constexpr void reverse() noexcept; \end{itemdecl} \begin{itemdescr} @@ -7829,21 +7861,24 @@ \indexlibrarymember{erase}{forward_list}% \begin{itemdecl} -template - typename forward_list::size_type +template + constexpr typename forward_list::size_type erase(forward_list& c, const U& value); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return erase_if(c, [\&](auto\& elem) \{ return elem == value; \});} +Equivalent to: +\begin{codeblock} +return erase_if(c, [&](const auto& elem) -> bool { return elem == value; }); +\end{codeblock} \end{itemdescr} \indexlibrarymember{erase_if}{forward_list}% \begin{itemdecl} template - typename forward_list::size_type + constexpr typename forward_list::size_type erase_if(forward_list& c, Predicate pred); \end{itemdecl} @@ -7853,82 +7888,175 @@ Equivalent to: \tcode{return c.remove_if(pred);} \end{itemdescr} -\rSec2[list]{Class template \tcode{list}} +\rSec2[hive.syn]{Header \tcode{} synopsis} -\rSec3[list.overview]{Overview} +\indexheader{hive}% +\begin{codeblock} + +#include // see \ref{initializer.list.syn} +#include // see \ref{compare.syn} + +namespace std { + struct @\libglobal{hive_limits}@ { + size_t @\libmember{min}{hive_limits}@; + size_t @\libmember{max}{hive_limits}@; + constexpr hive_limits(size_t minimum, size_t maximum) noexcept + : min(minimum), max(maximum) {} + }; + + // \ref {hive}, class template \tcode{hive} + template> class hive; + + template + void swap(hive& x, hive& y) + noexcept(noexcept(x.swap(y))); + + template + typename hive::size_type + erase(hive& c, const U& value); + + template + typename hive::size_type + erase_if(hive& c, Predicate pred); + + namespace pmr { + template + using hive = std::hive>; + } +} +\end{codeblock} + +\rSec2[hive]{Class template \tcode{hive}} + +\rSec3[hive.overview]{Overview} \pnum -\indexlibraryglobal{list}% -A -\tcode{list} -is a sequence container that supports -bidirectional iterators and allows constant time insert and erase -operations anywhere within the sequence, with storage management handled -automatically. Unlike vectors\iref{vector} and deques\iref{deque}, -fast random access to list elements is not supported, but many -algorithms only need sequential access anyway. +A \tcode{hive} is a type of sequence container +that provides constant-time insertion and erasure operations. +Storage is automatically managed in multiple memory blocks, +referred to as \defnx{element blocks}{element block}. +Insertion position is determined by the container, and insertion +may re-use the memory locations of erased elements. \pnum -A \tcode{list} meets all of the requirements -of a container\iref{container.reqmts}, +Element blocks which contain elements are referred to +as \defnadjx{active}{blocks}{block}, +those which do not are referred to as \defnadjx{reserved}{blocks}{block}. +Active blocks which become empty of elements are +either deallocated or become reserved blocks. +Reserved blocks become active blocks when they are used to store elements. +A user can create additional reserved blocks by calling \tcode{reserve}. + +\pnum +Erasures use unspecified techniques of constant time complexity +to identify the memory locations of erased elements, +which are subsequently skipped during iteration, +as opposed to relocating subsequent elements during erasure. + +\pnum +Active block capacities have +an \impldef{growth factor of \tcode{hive} active block capacities} growth factor +(which need not be integral), +for example a new active block's capacity could be equal to +the summed capacities of the pre-existing active blocks. + +\pnum +Limits can be placed on +both the minimum and maximum element capacities of element blocks, +both by users and implementations. +\begin{itemize} +\item +The minimum limit shall be no larger than the maximum limit. +\item +When limits are not specified by a user during construction, +the implementation's default limits are used. +\item +The default limits of an implementation are not guaranteed to be the same as +the minimum and maximum possible capacities +for an implementation's element blocks. +\begin{note} +To allow latitude for +both implementation-specific and user-directed optimization. +\end{note} +The latter are defined as hard limits. +The maximum hard limit shall be no larger than +\tcode{std::allocator_traits::max_size()}. +\item +If user-specified limits are not within hard limits, or +if the specified minimum limit is greater than the specified maximum limit, +the behavior is undefined. +\item +An element block is said to be \defnx{within the bounds}{element block!bounds} +of a pair of minimum/maximum limits +when its capacity is greater-or-equal-to the minimum limit and +less-than-or-equal-to the maximum limit. +\end{itemize} + +\pnum +A \tcode{hive} conforms to +the requirements for containers\iref{container.reqmts}, +with the exception of operators \tcode{==} and \tcode{!=}. +A \tcode{hive} also meets the requirements of a reversible container\iref{container.rev.reqmts}, of an allocator-aware container\iref{container.alloc.reqmts}, and -of a sequence container, -including most of the optional sequence container -requirements\iref{sequence.reqmts}. -The exceptions are the -\tcode{operator[]} -and -\tcode{at} -member functions, which are not provided. -\begin{footnote} -These member functions -are only provided by containers whose iterators -are random access iterators. -\end{footnote} -Descriptions are provided here only for operations on -\tcode{list} -that are not described in one of these tables -or for operations where there is additional semantic information. +some of the requirements of a sequence container\iref{sequence.reqmts}. +Descriptions are provided here only for operations on \tcode{hive} +that are not described in that table or for operations +where there is additional semantic information. + +\pnum +The iterators of \tcode{hive} meet +the \oldconcept{BidirectionalIterator} requirements +but also model \tcode{\libconcept{three_way_comparable}}. \begin{codeblock} namespace std { template> - class list { + class @\libglobal{hive}@ { public: // types - using value_type = T; - using allocator_type = Allocator; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; - using reference = value_type&; - using const_reference = const value_type&; - using size_type = @\impdefx{type of \tcode{list::size_type}}@; // see \ref{container.requirements} - using difference_type = @\impdefx{type of \tcode{list::difference_type}}@; // see \ref{container.requirements} - using iterator = @\impdefx{type of \tcode{list::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{list::const_iterator}}@; // see \ref{container.requirements} - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - // \ref{list.cons}, construct/copy/destroy - list() : list(Allocator()) { } - explicit list(const Allocator&); - explicit list(size_type n, const Allocator& = Allocator()); - list(size_type n, const T& value, const Allocator& = Allocator()); + using value_type = T; + using allocator_type = Allocator; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = @\impdef@; // see \ref{container.requirements} + using difference_type = @\impdef@; // see \ref{container.requirements} + using iterator = @\impdef@; // see \ref{container.requirements} + using const_iterator = @\impdef@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; // see \ref{container.requirements} + using const_reverse_iterator = std::reverse_iterator; // see \ref{container.requirements} + + // \ref{hive.cons}, construct/copy/destroy + constexpr hive() noexcept(noexcept(Allocator())) : hive(Allocator()) {} + constexpr explicit hive(const Allocator&) noexcept; + constexpr explicit hive(hive_limits block_limits) : hive(block_limits, Allocator()) {} + constexpr hive(hive_limits block_limits, const Allocator&); + explicit hive(size_type n, const Allocator& = Allocator()); + hive(size_type n, hive_limits block_limits, const Allocator& = Allocator()); + hive(size_type n, const T& value, const Allocator& = Allocator()); + hive(size_type n, const T& value, hive_limits block_limits, const Allocator& = Allocator()); template - list(InputIterator first, InputIterator last, const Allocator& = Allocator()); + hive(InputIterator first, InputIterator last, const Allocator& = Allocator()); + template + hive(InputIterator first, InputIterator last, hive_limits block_limits, + const Allocator& = Allocator()); template<@\exposconcept{container-compatible-range}@ R> - list(from_range_t, R&& rg, const Allocator& = Allocator()); - list(const list& x); - list(list&& x); - list(const list&, const type_identity_t&); - list(list&&, const type_identity_t&); - list(initializer_list, const Allocator& = Allocator()); - ~list(); - list& operator=(const list& x); - list& operator=(list&& x) - noexcept(allocator_traits::is_always_equal::value); - list& operator=(initializer_list); + hive(from_range_t, R&& rg, const Allocator& = Allocator()); + template<@\exposconcept{container-compatible-range}@ R> + hive(from_range_t, R&& rg, hive_limits block_limits, const Allocator& = Allocator()); + hive(const hive& x); + hive(hive&&) noexcept; + hive(const hive& x, const type_identity_t& alloc); + hive(hive&&, const type_identity_t& alloc); + hive(initializer_list il, const Allocator& = Allocator()); + hive(initializer_list il, hive_limits block_limits, const Allocator& = Allocator()); + ~hive(); + + hive& operator=(const hive& x); + hive& operator=(hive&& x) noexcept(@\seebelow@); + hive& operator=(initializer_list); template void assign(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> @@ -7938,1332 +8066,1052 @@ 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; - - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() const noexcept; - - // \ref{list.capacity}, capacity - [[nodiscard]] bool empty() const noexcept; + 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; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + // \ref{hive.capacity}, capacity + bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; - void resize(size_type sz); - void resize(size_type sz, const T& c); - - // element access - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - // \ref{list.modifiers}, modifiers - template reference emplace_front(Args&&... args); - template reference emplace_back(Args&&... args); - void push_front(const T& x); - void push_front(T&& x); - template<@\exposconcept{container-compatible-range}@ R> - void prepend_range(R&& rg); - void pop_front(); - void push_back(const T& x); - void push_back(T&& x); + size_type capacity() const noexcept; + void reserve(size_type n); + void shrink_to_fit(); + void trim_capacity() noexcept; + void trim_capacity(size_type n) noexcept; + constexpr hive_limits block_capacity_limits() const noexcept; + static constexpr hive_limits block_capacity_default_limits() noexcept; + static constexpr hive_limits block_capacity_hard_limits() noexcept; + void reshape(hive_limits block_limits); + + // \ref{hive.modifiers}, modifiers + template iterator emplace(Args&&... args); + template iterator emplace_hint(const_iterator hint, Args&&... args); + iterator insert(const T& x); + iterator insert(T&& x); + iterator insert(const_iterator hint, const T& x); + iterator insert(const_iterator hint, T&& x); + void insert(initializer_list il); template<@\exposconcept{container-compatible-range}@ R> - void append_range(R&& rg); - 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); + void insert_range(R&& rg); template - iterator insert(const_iterator position, InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - iterator insert_range(const_iterator position, R&& rg); - iterator insert(const_iterator position, initializer_list il); + void insert(InputIterator first, InputIterator last); + void insert(size_type n, const T& x); iterator erase(const_iterator position); - iterator erase(const_iterator position, const_iterator last); - void swap(list&) noexcept(allocator_traits::is_always_equal::value); - void clear() noexcept; + iterator erase(const_iterator first, const_iterator last); + void swap(hive&) noexcept(@\seebelow@); + void clear() noexcept; - // \ref{list.ops}, list operations - void splice(const_iterator position, list& x); - void splice(const_iterator position, list&& x); - void splice(const_iterator position, list& x, const_iterator i); - void splice(const_iterator position, list&& x, const_iterator i); - void splice(const_iterator position, list& x, const_iterator first, const_iterator last); - void splice(const_iterator position, list&& x, const_iterator first, const_iterator last); + // \ref{hive.operations}, hive operations + void splice(hive& x); + void splice(hive&& x); + template> + size_type unique(BinaryPredicate binary_pred = BinaryPredicate()); - size_type remove(const T& value); - template size_type remove_if(Predicate pred); + template> + void sort(Compare comp = Compare()); - size_type unique(); - template - size_type unique(BinaryPredicate binary_pred); + iterator get_iterator(const_pointer p) noexcept; + const_iterator get_iterator(const_pointer p) const noexcept; - void merge(list& x); - void merge(list&& x); - template void merge(list& x, Compare comp); - template void merge(list&& x, Compare comp); + private: + hive_limits @\exposid{current-limits}@ = @\impdef@; // \expos + }; - void sort(); - template void sort(Compare comp); + template>> + hive(InputIterator, InputIterator, Allocator = Allocator()) + -> hive<@\exposid{iter-value-type}@, Allocator>; - void reverse() noexcept; - }; + template>> + hive(InputIterator, InputIterator, hive_limits, Allocator = Allocator()) + -> hive<@\exposid{iter-value-type}@, Allocator>; - template>> - list(InputIterator, InputIterator, Allocator = Allocator()) - -> list<@\placeholder{iter-value-type}@, Allocator>; + template>> + hive(from_range_t, R&&, Allocator = Allocator()) + -> hive, Allocator>; template>> - list(from_range_t, R&&, Allocator = Allocator()) - -> list, Allocator>; + hive(from_range_t, R&&, hive_limits, Allocator = Allocator()) + -> hive, Allocator>; } \end{codeblock} +\rSec3[hive.cons]{Constructors, copy, and assignment} + +\indexlibraryctor{hive}% +\begin{itemdecl} +constexpr explicit hive(const Allocator&) noexcept; +\end{itemdecl} + +\begin{itemdescr} \pnum -An incomplete type \tcode{T} may be used when instantiating \tcode{list} -if the allocator meets the -allocator completeness requirements\iref{allocator.requirements.completeness}. -\tcode{T} shall be complete before any member of the resulting specialization -of \tcode{list} is referenced. +\effects +Constructs an empty \tcode{hive}, using the specified allocator. -\rSec3[list.cons]{Constructors, copy, and assignment} +\pnum +\complexity +Constant. +\end{itemdescr} -\indexlibraryctor{list}% +\indexlibraryctor{hive}% \begin{itemdecl} -explicit list(const Allocator&); +constexpr hive(hive_limits block_limits, const Allocator&); \end{itemdecl} \begin{itemdescr} \pnum \effects -Constructs an empty list, using the specified allocator. +Constructs an empty \tcode{hive}, using the specified allocator. +Initializes \exposid{current-limits} with \tcode{block_limits}. \pnum \complexity Constant. \end{itemdescr} -\indexlibraryctor{list}% +\indexlibraryctor{hive}% \begin{itemdecl} -explicit list(size_type n, const Allocator& = Allocator()); +explicit hive(size_type n, const Allocator& = Allocator()); +hive(size_type n, hive_limits block_limits, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{hive}. \pnum \effects -Constructs a \tcode{list} with -\tcode{n} default-inserted elements using the specified allocator. +Constructs a \tcode{hive} with \tcode{n} default-inserted elements, +using the specified allocator. +If the second overload is called, +also initializes \exposid{current-limits} with \tcode{block_limits}. \pnum \complexity -Linear in -\tcode{n}. +Linear in \tcode{n}. \end{itemdescr} -\indexlibraryctor{list}% +\indexlibraryctor{hive}% \begin{itemdecl} -list(size_type n, const T& value, const Allocator& = Allocator()); +hive(size_type n, const T& value, const Allocator& = Allocator()); +hive(size_type n, const T& value, hive_limits block_limits, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{CopyInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{hive}. \pnum \effects -Constructs a -\tcode{list} -with -\tcode{n} -copies of -\tcode{value}, +Constructs a \tcode{hive} with \tcode{n} copies of \tcode{value}, using the specified allocator. +If the second overload is called, +also initializes \exposid{current-limits} with \tcode{block_limits}. \pnum \complexity -Linear in -\tcode{n}. +Linear in \tcode{n}. \end{itemdescr} -\indexlibraryctor{list}% +\indexlibraryctor{hive}% \begin{itemdecl} template - list(InputIterator first, InputIterator last, const Allocator& = Allocator()); + hive(InputIterator first, InputIterator last, const Allocator& = Allocator()); +template + hive(InputIterator first, InputIterator last, hive_limits block_limits, + const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \effects -Constructs a -\tcode{list} -equal to the range -\range{first}{last}. +Constructs a \tcode{hive} equal to the range \range{first}{last}, +using the specified allocator. +If the second overload is called, +also initializes \exposid{current-limits} with \tcode{block_limits}. \pnum \complexity -Linear in -\tcode{distance(first, last)}. +Linear in \tcode{distance(first, last)}. \end{itemdescr} -\indexlibraryctor{list}% +\indexlibraryctor{hive}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - list(from_range_t, R&& rg, const Allocator& = Allocator()); + hive(from_range_t, R&& rg, const Allocator& = Allocator()); +template<@\exposconcept{container-compatible-range}@ R> + hive(from_range_t, R&& rg, hive_limits block_limits, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \effects -Constructs a \tcode{list} object with the elements of the range \tcode{rg}. +Constructs a \tcode{hive} object with the elements of the range \tcode{rg}, +using the specified allocator. +If the second overload is called, +also initializes \exposid{current-limits} with \tcode{block_limits}. \pnum \complexity Linear in \tcode{ranges::distance(rg)}. \end{itemdescr} -\rSec3[list.capacity]{Capacity} - -\indexlibrarymember{resize}{list}% +\indexlibraryctor{hive}% \begin{itemdecl} -void resize(size_type sz); +hive(const hive& x); +hive(const hive& x, const type_identity_t& alloc); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{hive}. \pnum \effects -If \tcode{size() < sz}, -appends \tcode{sz - size()} default-inserted elements to the -sequence. -If \tcode{sz <= size()}, equivalent to: +Constructs a \tcode{hive} object with the elements of \tcode{x}. +If the second overload is called, uses \tcode{alloc}. +Initializes \exposid{current-limits} with \tcode{x.\exposid{current-limits}}. -\begin{codeblock} -list::iterator it = begin(); -advance(it, sz); -erase(it, end()); -\end{codeblock} +\pnum +\complexity +Linear in \tcode{x.size()}. \end{itemdescr} -\indexlibrarymember{resize}{list}% +\indexlibraryctor{hive}% \begin{itemdecl} -void resize(size_type sz, const T& c); +hive(hive&& x); +hive(hive&& x, const type_identity_t& alloc); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{CopyInsertable} into \tcode{*this}. +For the second overload, +when \tcode{allocator_traits::is_always_equal::value} is \tcode{false}, +\tcode{T} meets the \oldconcept{MoveInsertable} requirements. \pnum \effects -As if by: -\begin{codeblock} -if (sz > size()) - insert(end(), sz-size(), c); -else if (sz < size()) { - iterator i = begin(); - advance(i, sz); - erase(i, end()); -} -else - ; // do nothing -\end{codeblock} -\end{itemdescr} - -\rSec3[list.modifiers]{Modifiers} +When the first overload is called, or +the second overload is called and +\tcode{alloc == x.get_allocator()} is \tcode{true}, +\exposid{current-limits} is set to \tcode{x.\exposid{current-limits}} and +each element block is moved from \tcode{x} into \tcode{*this}. +Pointers and references to the elements of \tcode{x} now refer to +those same elements but as members of \tcode{*this}. +Iterators referring to the elements of \tcode{x} +will continue to refer to their elements, +but they now behave as iterators into \tcode{*this}. -\indexlibrarymember{insert}{list}% -\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); -template - iterator insert(const_iterator position, InputIterator first, - InputIterator last); -template<@\exposconcept{container-compatible-range}@ R> - iterator insert_range(const_iterator position, R&& rg); -iterator insert(const_iterator position, initializer_list); - -template reference emplace_front(Args&&... args); -template reference emplace_back(Args&&... args); -template iterator emplace(const_iterator position, Args&&... args); -void push_front(const T& x); -void push_front(T&& x); -template<@\exposconcept{container-compatible-range}@ R> - void prepend_range(R&& rg); -void push_back(const T& x); -void push_back(T&& x); -template<@\exposconcept{container-compatible-range}@ R> - void append_range(R&& rg); -\end{itemdecl} +If the second overload is called and +\tcode{alloc == x.get_allocator()} is \tcode{false}, +each element in \tcode{x} is moved into \tcode{*this}. +References, pointers and iterators referring to the elements of \tcode{x}, as well as the past-the-end iterator of \tcode{x}, are invalidated. -\begin{itemdescr} \pnum -\complexity -Insertion of a single element into a list takes constant time and -exactly one call to a constructor of -\tcode{T}. Insertion of multiple elements into a list is linear in the -number of elements inserted, and the number of calls to the copy -constructor or move constructor of \tcode{T} is exactly equal -to the number of elements inserted. +\ensures +\tcode{x.empty()} is \tcode{true}. \pnum -\remarks -Does not affect the validity of iterators and references. -If an exception is thrown there are no effects. +\complexity +If the second overload is called and +\tcode{alloc == x.get_allocator()} is \tcode{false}, linear in \tcode{x.size()}. +Otherwise constant. \end{itemdescr} -\indexlibrarymember{erase}{list}% +\indexlibraryctor{hive}% \begin{itemdecl} -iterator erase(const_iterator position); -iterator erase(const_iterator first, const_iterator last); - -void pop_front(); -void pop_back(); -void clear() noexcept; +hive(initializer_list il, const Allocator& = Allocator()); +hive(initializer_list il, hive_limits block_limits, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Invalidates only the iterators and references to the erased elements. +\expects +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{hive}. \pnum -\throws -Nothing. +\effects +Constructs a \tcode{hive} object with the elements of \tcode{il}, +using the specified allocator. +If the second overload is called, +also initializes \exposid{current-limits} with \tcode{block_limits}. \pnum \complexity -Erasing a single element is a constant time operation with a single call to the destructor of -\tcode{T}. -Erasing a range in a list is linear time in the -size of the range and the number of calls to the destructor of type -\tcode{T} -is exactly equal to the size of the range. +Linear in \tcode{il.size()}. \end{itemdescr} -\rSec3[list.ops]{Operations} - -\pnum -Since lists allow fast insertion and erasing from the middle of a list, certain -operations are provided specifically for them. -\begin{footnote} -As specified -in~\ref{allocator.requirements}, the requirements in this Clause apply only to -lists whose allocators compare equal. -\end{footnote} -In this subclause, -arguments for a template parameter -named \tcode{Predicate} or \tcode{BinaryPredicate} -shall meet the corresponding requirements in \ref{algorithms.requirements}. -The semantics of \tcode{i + n} and \tcode{i - n}, -where \tcode{i} is an iterator into the list and \tcode{n} is an integer, -are the same as those of \tcode{next(i, n)} and \tcode{prev(i, n)}, -respectively. -For \tcode{merge} and \tcode{sort}, -the definitions and requirements in \ref{alg.sorting} apply. - -\pnum -\tcode{list} provides three splice operations that destructively move elements from one list to -another. The behavior of splice operations is undefined if \tcode{get_allocator() != -x.get_allocator()}. - -\indexlibrarymember{splice}{list}% +\indexlibrarymember{operator=}{hive}% \begin{itemdecl} -void splice(const_iterator position, list& x); -void splice(const_iterator position, list&& x); +hive& operator=(const hive& x); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{addressof(x) != this} is \tcode{true}. +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{hive} and +\oldconcept{CopyAssignable}. \pnum \effects -Inserts the contents of -\tcode{x} -before -\tcode{position} -and -\tcode{x} -becomes empty. -Pointers and references to the moved elements of -\tcode{x} -now refer to those same elements but as members of -\tcode{*this}. -Iterators referring to the moved elements will continue to refer to their -elements, but they now behave as iterators into -\tcode{*this}, -not into -\tcode{x}. - -\pnum -\throws -Nothing. +All elements in \tcode{*this} are either copy-assigned to, or destroyed. +All elements in \tcode{x} are copied into \tcode{*this}. +\begin{note} +\exposid{current-limits} is unchanged. +\end{note} \pnum \complexity -Constant time. +Linear in \tcode{size() + x.size()}. \end{itemdescr} -\indexlibrarymember{splice}{list}% +\indexlibrarymember{operator=}{hive}% \begin{itemdecl} -void splice(const_iterator position, list& x, const_iterator i); -void splice(const_iterator position, list&& x, const_iterator i); +hive& operator=(hive&& x) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{i} is a valid dereferenceable iterator of \tcode{x}. +When +\begin{codeblock} +(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value) +\end{codeblock} +is \tcode{false}, +\tcode{T} is \oldconcept{MoveInsertable} into \tcode{hive} and +\oldconcept{MoveAssignable}. \pnum \effects -Inserts an element pointed to by -\tcode{i} -from list -\tcode{x} -before \tcode{position} and removes the element from -\tcode{x}. -The result is unchanged if -\tcode{position == i} -or -\tcode{position == ++i}. -Pointers and references to -\tcode{*i} -continue to refer to this same element but as a member of -\tcode{*this}. -Iterators -to -\tcode{*i} -(including -\tcode{i} -itself) continue to refer to the same element, but now behave as iterators into -\tcode{*this}, -not into -\tcode{x}. +Each element in \tcode{*this} is either move-assigned to, or destroyed. +When +\begin{codeblock} +(allocator_traits::propagate_on_container_move_assignment::value || + get_allocator() == x.get_allocator()) +\end{codeblock} +is \tcode{true}, +\exposid{current-limits} is set to \tcode{x.\exposid{current-limits}} and +each element block is moved from \tcode{x} into \tcode{*this}. +Pointers and references to the elements of \tcode{x} +now refer to those same elements but as members of \tcode{*this}. +Iterators referring to the elements of \tcode{x} +will continue to refer to their elements, +but they now behave as iterators into \tcode{*this}, not into \tcode{x}. + +When +\begin{codeblock} +(allocator_traits::propagate_on_container_move_assignment::value || + get_allocator() == x.get_allocator()) +\end{codeblock} +is \tcode{false}, +each element in \tcode{x} is moved into \tcode{*this}. +References, pointers and iterators referring to the elements of \tcode{x}, +as well as the past-the-end iterator of \tcode{x}, are invalidated. \pnum -\throws -Nothing. +\ensures +\tcode{x.empty()} is \tcode{true}. \pnum \complexity -Constant time. +Linear in \tcode{size()}. +If +\begin{codeblock} +(allocator_traits::propagate_on_container_move_assignment::value || + get_allocator() == x.get_allocator()) +\end{codeblock} +is \tcode{false}, also linear in \tcode{x.size()}. \end{itemdescr} -\indexlibrarymember{splice}{list}% +\rSec3[hive.capacity]{Capacity} + +\indexlibrarymember{capacity}{hive}% \begin{itemdecl} -void splice(const_iterator position, list& x, const_iterator first, - const_iterator last); -void splice(const_iterator position, list&& x, const_iterator first, - const_iterator last); +size_type capacity() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{[first, last)} is a valid range in \tcode{x}. -\tcode{position} is not an iterator in the range \range{first}{last}. - -\pnum -\effects -Inserts elements in the range -\range{first}{last} -before -\tcode{position} -and removes the elements from -\tcode{x}. -Pointers and references to the moved elements of -\tcode{x} -now refer to those same elements but as members of -\tcode{*this}. -Iterators referring to the moved elements will continue to refer to their -elements, but they now behave as iterators into -\tcode{*this}, -not into -\tcode{x}. - -\pnum -\throws -Nothing. +\returns +The total number of elements that \tcode{*this} can hold +without requiring allocation of more element blocks. \pnum \complexity -Constant time if -\tcode{addressof(x) == this}; -otherwise, linear time. +Constant. \end{itemdescr} -\indexlibrarymember{remove}{list}% +\indexlibrarymember{reserve}{hive}% \begin{itemdecl} -size_type remove(const T& value); -template size_type remove_if(Predicate pred); +void reserve(size_type n); \end{itemdecl} \begin{itemdescr} \pnum \effects -Erases all the elements in the list referred to by a list iterator \tcode{i} for which the -following conditions hold: \tcode{*i == value}, \tcode{pred(*i) != false}. -Invalidates only the iterators and references to the erased elements. +If \tcode{n <= capacity()} is \tcode{true}, there are no effects. +Otherwise increases \tcode{capacity()} by allocating reserved blocks. \pnum -\returns -The number of elements erased. +\ensures +\tcode{capacity() >= n} is \tcode{true}. \pnum \throws -Nothing unless an exception is thrown by -\tcode{*i == value} -or -\tcode{pred(*i) != false}. +\tcode{length_error} if \tcode{n > max_size()}, +as well as any exceptions thrown by the allocator. \pnum \complexity -Exactly -\tcode{size()} -applications of the corresponding predicate. +It does not change the size of the sequence and +takes at most linear time in the number of reserved blocks allocated. \pnum \remarks -Stable\iref{algorithm.stable}. +All references, pointers, and iterators referring to elements in \tcode{*this}, +as well as the past-the-end iterator, remain valid. \end{itemdescr} -\indexlibrarymember{unique}{list}% +\indexlibrarymember{shrink_to_fit}{hive}% \begin{itemdecl} -size_type unique(); -template size_type unique(BinaryPredicate binary_pred); +void shrink_to_fit(); \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{binary_pred} be \tcode{equal_to<>\{\}} for the first overload. - \pnum \expects -\tcode{binary_pred} is an equivalence relation. +\tcode{T} is \oldconcept{MoveInsertable} into \tcode{hive}. \pnum \effects -Erases all but the first element from every -consecutive group of equivalent elements. -That is, for a nonempty list, erases all elements referred to -by the iterator \tcode{i} in the range \range{begin() + 1}{end()} -for which \tcode{binary_pred(*i, *(i - 1))} is \tcode{true}. -Invalidates only the iterators and references to the erased elements. +\tcode{shrink_to_fit} is a non-binding request +to reduce \tcode{capacity()} to be closer to \tcode{size()}. +\begin{note} +The request is non-binding +to allow latitude for implementation-specific optimizations. +\end{note} +It does not increase \tcode{capacity()}, but may reduce \tcode{capacity()}. +It may reallocate elements. +If \tcode{capacity()} is already equal to \tcode{size()}, there are no effects. +If an exception is thrown during allocation of a new element block, +\tcode{capacity()} may be reduced and reallocation may occur. +Otherwise if an exception is thrown, the effects are unspecified. \pnum -\returns -The number of elements erased. +\complexity +If reallocation happens, linear in the size of the sequence. \pnum -\throws -Nothing unless an exception is thrown by the predicate. +\remarks +If reallocation happens, +the order of the elements in \tcode{*this} may change and +all references, pointers, and iterators +referring to the elements in \tcode{*this}, +as well as the past-the-end iterator, are invalidated. +\end{itemdescr} -\pnum +\indexlibrarymember{trim_capacity}{hive}% +\begin{itemdecl} +void trim_capacity() noexcept; +void trim_capacity(size_type n) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +For the first overload, all reserved blocks are deallocated, and +\tcode{capacity()} is reduced accordingly. +For the second overload, \tcode{capacity()} is reduced to no less than \tcode{n}. + +\pnum \complexity -If \tcode{empty()} is \tcode{false}, -exactly \tcode{size() - 1} applications of the corresponding predicate, -otherwise no applications of the predicate. +Linear in the number of reserved blocks deallocated. + +\pnum +\remarks +All references, pointers, and iterators referring to elements in \tcode{*this}, +as well as the past-the-end iterator, remain valid. \end{itemdescr} -\indexlibrarymember{merge}{list}% +\indexlibrarymember{block_capacity_limits}{hive}% \begin{itemdecl} -void merge(list& x); -void merge(list&& x); -template void merge(list& x, Compare comp); -template void merge(list&& x, Compare comp); +constexpr hive_limits block_capacity_limits() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{comp} be \tcode{less<>{}} for the first two overloads. +\returns +\exposid{current-limits}. \pnum -\expects -\tcode{*this} and \tcode{x} are both sorted -with respect to the comparator \tcode{comp}, and -\tcode{get_allocator() == x.get_allocator()} is \tcode{true}. +\complexity +Constant. +\end{itemdescr} -\pnum -\effects -If \tcode{addressof(x) == this}, there are no effects. -Otherwise, merges -the two sorted ranges \range{begin()}{end()} and \range{x.begin()}{x.end()}. -The result is a range -that is sorted with respect to the comparator \tcode{comp}. -Pointers and references to the moved elements of \tcode{x} now refer to those same elements -but as members of \tcode{*this}. Iterators referring to the moved elements will continue to -refer to their elements, but they now behave as iterators into \tcode{*this}, not into -\tcode{x}. +\indexlibrarymember{block_capacity_default_limits}{hive}% +\begin{itemdecl} +static constexpr hive_limits block_capacity_default_limits() noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\complexity -At most \tcode{size() + x.size() - 1} comparisons -if \tcode{addressof(x) != this}; -otherwise, no comparisons are performed. +\returns +A \tcode{hive_limits} struct +with the \tcode{min} and \tcode{max} members set to +the implementation's default limits. \pnum -\remarks -Stable\iref{algorithm.stable}. -If \tcode{addressof(x) != this}, \tcode{x} is empty after the merge. -No elements are copied by this operation. -If an exception is thrown other than by a comparison there are no effects. +\complexity +Constant. \end{itemdescr} -\indexlibrarymember{reverse}{list}% +\indexlibrarymember{block_capacity_hard_limits}{hive}% \begin{itemdecl} -void reverse() noexcept; +static constexpr hive_limits block_capacity_hard_limits() noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Reverses the order of the elements in the list. -Does not affect the validity of iterators and references. +\returns +A \tcode{hive_limits} struct +with the \tcode{min} and \tcode{max} members set to +the implementation's hard limits. \pnum \complexity -Linear time. +Constant. \end{itemdescr} -\indexlibrarymember{sort}{list}% +\indexlibrarymember{reshape}{hive}% \begin{itemdecl} -void sort(); -template void sort(Compare comp); +void reshape(hive_limits block_limits); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{MoveInsertable} into \tcode{hive}. + \pnum \effects -Sorts the list according to the \tcode{operator<} or a \tcode{Compare} function object. -If an exception is thrown, -the order of the elements in \tcode{*this} is unspecified. -Does not affect the validity of iterators and references. +For any active blocks not within the bounds of \tcode{block_limits}, +the elements within those active blocks are reallocated +to new or existing element blocks which are within the bounds. +Any element blocks not within the bounds of \tcode{block_limits} +are deallocated. +If an exception is thrown during allocation of a new element block, +\tcode{capacity()} may be reduced, +reallocation may occur, and +\exposid{current-limits} may be assigned +a value other than \tcode{block_limits}. +Otherwise \tcode{block_limits} is assigned to \exposid{current-limits}. +If any other exception is thrown the effects are unspecified. + +\pnum +\ensures +\tcode{size()} is unchanged. \pnum \complexity -Approximately -$N \log N$ -comparisons, where -\tcode{N == size()}. +Linear in the number of element blocks in \tcode{*this}. +If reallocation happens, also linear in the number of elements reallocated. \pnum \remarks -Stable\iref{algorithm.stable}. +This operation may change \tcode{capacity()}. +If reallocation happens, the order of the elements in \tcode{*this} may change. +Reallocation invalidates all references, pointers, and iterators +referring to the elements in \tcode{*this}, +as well as the past-the-end iterator. +\begin{note} +If no reallocation happens, they remain valid. +\end{note} \end{itemdescr} -\rSec3[list.erasure]{Erasure} +\rSec3[hive.modifiers]{Modifiers} -\indexlibrarymember{erase}{list}% +\indexlibrarymember{emplace}{hive}% \begin{itemdecl} -template - typename list::size_type - erase(list& c, const U& value); +template iterator emplace(Args&&... args); +template iterator emplace_hint(const_iterator hint, Args&&... args); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{EmplaceConstructible} into \tcode{hive} from \tcode{args}. + \pnum \effects -Equivalent to: \tcode{return erase_if(c, [\&](auto\& elem) \{ return elem == value; \});} +Inserts an object of type \tcode{T} +constructed with \tcode{std::forward(args)...}. +The \tcode{hint} parameter is ignored. +If an exception is thrown, there are no effects. +\begin{note} +\tcode{args} can directly or indirectly refer to a value in \tcode{*this}. +\end{note} + +\pnum +\returns +An iterator that points to the new element. + +\pnum +\complexity +Constant. Exactly one object of type \tcode{T} is constructed. + +\pnum +\remarks +Invalidates the past-the-end iterator. \end{itemdescr} -\indexlibrarymember{erase_if}{list}% +\indexlibrarymember{insert}{hive}% \begin{itemdecl} -template - typename list::size_type - erase_if(list& c, Predicate pred); +iterator insert(const T& x); +iterator insert(const_iterator hint, const T& x); +iterator insert(T&& x); +iterator insert(const_iterator hint, T&& x); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return c.remove_if(pred);} +Equivalent to: \tcode{return emplace(std::forward(x));} +\begin{note} +The \tcode{hint} parameter is ignored. +\end{note} \end{itemdescr} -\rSec2[vector]{Class template \tcode{vector}} +\indexlibrarymember{insert}{hive}% +\begin{itemdecl} +void insert(initializer_list rg); +template<@\exposconcept{container-compatible-range}@ R> + void insert_range(R&& rg); +\end{itemdecl} -\rSec3[vector.overview]{Overview} +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{EmplaceInsertable} into \tcode{hive} +from \tcode{*ranges::begin(rg)}. +\tcode{rg} and \tcode{*this} do not overlap. \pnum -\indexlibraryglobal{vector}% -A -\tcode{vector} -is a sequence container that supports -(amortized) constant time insert and erase operations at the end; -insert and erase in the middle take linear time. -Storage management is handled automatically, though hints can be given -to improve efficiency. +\effects +Inserts copies of elements in \tcode{rg}. +Each iterator in the range \tcode{rg} is dereferenced exactly once. \pnum -A \tcode{vector} meets all of the requirements -of a container\iref{container.reqmts}, -of a reversible container\iref{container.rev.reqmts}, -of an allocator-aware container\iref{container.alloc.reqmts}, -of a sequence container, including most of the optional sequence container -requirements\iref{sequence.reqmts}, -and, for an element type other than \tcode{bool}, -of a contiguous container\iref{container.reqmts}. -The exceptions are the -\tcode{push_front}, \tcode{prepend_range}, \tcode{pop_front}, and \tcode{emplace_front} member functions, which are not -provided. Descriptions are provided here only for operations on \tcode{vector} -that are not described in one of these tables or for operations where there is -additional semantic information. +\complexity +Linear in the number of elements inserted. +Exactly one object of type \tcode{T} is constructed for each element inserted. \pnum -The types \tcode{iterator} and \tcode{const_iterator} meet -the constexpr iterator requirements\iref{iterator.requirements.general}. +\remarks +If an element is inserted, invalidates the past-the-end iterator. +\end{itemdescr} -\begin{codeblock} -namespace std { - template> - class vector { - public: - // types - using value_type = T; - using allocator_type = Allocator; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; - using reference = value_type&; - using const_reference = const value_type&; - using size_type = @\impdefx{type of \tcode{vector::size_type}}@; // see \ref{container.requirements} - using difference_type = @\impdefx{type of \tcode{vector::difference_type}}@; // see \ref{container.requirements} - using iterator = @\impdefx{type of \tcode{vector::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{vector::const_iterator}}@; // see \ref{container.requirements} - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; +\indexlibrarymember{insert}{hive}% +\begin{itemdecl} +void insert(size_type n, const T& x); +\end{itemdecl} - // \ref{vector.cons}, construct/copy/destroy - 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 - constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); - template<@\exposconcept{container-compatible-range}@ R> - constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); - constexpr vector(const vector& x); - constexpr vector(vector&&) noexcept; - constexpr vector(const vector&, const type_identity_t&); - constexpr vector(vector&&, const type_identity_t&); - 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); - constexpr vector& operator=(initializer_list); - template - constexpr void assign(InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - constexpr void assign_range(R&& rg); - constexpr void assign(size_type n, const T& u); - constexpr void assign(initializer_list); - constexpr allocator_type get_allocator() const noexcept; +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{hive}. - // iterators - 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; +\pnum +\effects +Inserts \tcode{n} copies of \tcode{x}. - 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; +\pnum +\complexity +Linear in \tcode{n}. +Exactly one object of type \tcode{T} is constructed for each element inserted. - // \ref{vector.capacity}, capacity - [[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(); +\pnum +\remarks +If an element is inserted, invalidates the past-the-end iterator. +\end{itemdescr} - // element access - 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; +\indexlibrarymember{insert}{hive}% +\begin{itemdecl} +template + void insert(InputIterator first, InputIterator last); +\end{itemdecl} - // \ref{vector.data}, data access - constexpr T* data() noexcept; - constexpr const T* data() const noexcept; +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{insert_range(ranges::subrange(first, last))}. +\end{itemdescr} - // \ref{vector.modifiers}, modifiers - template constexpr reference emplace_back(Args&&... args); - constexpr void push_back(const T& x); - constexpr void push_back(T&& x); - template<@\exposconcept{container-compatible-range}@ R> - constexpr void append_range(R&& rg); - 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 - constexpr iterator insert(const_iterator position, - InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - constexpr iterator insert_range(const_iterator position, R&& rg); - 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); - constexpr void clear() noexcept; - }; - - template>> - vector(InputIterator, InputIterator, Allocator = Allocator()) - -> vector<@\placeholder{iter-value-type}@, Allocator>; - - template>> - vector(from_range_t, R&&, Allocator = Allocator()) - -> vector, Allocator>; -} -\end{codeblock}% -\indexlibrarymember{vector}{operator==}% -\indexlibrarymember{vector}{operator<} - -\pnum -An incomplete type \tcode{T} may be used when instantiating \tcode{vector} -if the allocator meets the -allocator completeness requirements\iref{allocator.requirements.completeness}. -\tcode{T} shall be complete before any member of the resulting specialization -of \tcode{vector} is referenced. - -\rSec3[vector.cons]{Constructors} - -\indexlibraryctor{vector} -\begin{itemdecl} -constexpr explicit vector(const Allocator&) noexcept; -\end{itemdecl} +\indexlibrarymember{erase}{hive}% +\begin{itemdecl} +iterator erase(const_iterator position); +iterator erase(const_iterator first, const_iterator last); +\end{itemdecl} \begin{itemdescr} \pnum -\effects -Constructs an empty \tcode{vector}, using the -specified allocator. +\complexity +Linear in the number of elements erased. +Additionally, if any active blocks become empty of elements +as a result of the function call, +at worst linear in the number of element blocks. \pnum -\complexity -Constant. +\remarks +Invalidates references, pointers and iterators +referring to the erased elements. +An erase operation that erases the last element in \tcode{*this} +also invalidates the past-the-end iterator. \end{itemdescr} -\indexlibraryctor{vector} +\indexlibrarymember{swap}{hive}% \begin{itemdecl} -constexpr explicit vector(size_type n, const Allocator& = Allocator()); +void swap(hive& x) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{*this}. - \pnum \effects -Constructs a \tcode{vector} with \tcode{n} -default-inserted elements using the specified allocator. +Exchanges the contents, \tcode{capacity()}, and \exposid{current-limits} +of \tcode{*this} with that of \tcode{x}. \pnum \complexity -Linear in \tcode{n}. +Constant. \end{itemdescr} -\indexlibraryctor{vector} -\begin{itemdecl} -constexpr vector(size_type n, const T& value, - const Allocator& = Allocator()); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{T} is -\oldconcept{CopyInsertable} into \tcode{*this}. - -\pnum -\effects -Constructs a \tcode{vector} with \tcode{n} -copies of \tcode{value}, using the specified allocator. +\rSec3[hive.operations]{Operations} -\pnum -\complexity -Linear in \tcode{n}. -\end{itemdescr} +In this subclause, +arguments for a template parameter +named \tcode{Predicate} or \tcode{BinaryPredicate} +shall meet the corresponding requirements in \ref{algorithms.requirements}. +The semantics of \tcode{i + n} and \tcode{i - n}, +where \tcode{i} is an iterator into the \tcode{hive} and \tcode{n} is an integer, +are the same as those of \tcode{next(i, n)} and \tcode{prev(i, n)}, respectively. +For \tcode{sort}, the definitions and requirements in \ref{alg.sorting} apply. -\indexlibraryctor{vector} +\indexlibrarymember{splice}{hive}% \begin{itemdecl} -template - constexpr vector(InputIterator first, InputIterator last, - const Allocator& = Allocator()); +void splice(hive& x); +void splice(hive&& x); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Constructs a \tcode{vector} equal to the -range \range{first}{last}, using the specified allocator. - -\pnum -\complexity -Makes only $N$ -calls to the copy constructor of -\tcode{T} -(where $N$ -is the distance between -\tcode{first} -and -\tcode{last}) -and no reallocations if iterators \tcode{first} and \tcode{last} are of forward, bidirectional, or random access categories. -It makes order -$N$ -calls to the copy constructor of -\tcode{T} -and order -$\log N$ -reallocations if they are just input iterators. -\end{itemdescr} - -\indexlibraryctor{vector}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); -\end{itemdecl} +\expects +\tcode{get_allocator() == x.get_allocator()} is \tcode{true}. -\begin{itemdescr} \pnum \effects -Constructs a \tcode{vector} object with the elements of the range \tcode{rg}, -using the specified allocator. +If \tcode{addressof(x) == this} is \tcode{true}, +the behavior is erroneous and there are no effects. +Otherwise, inserts the contents of \tcode{x} into \tcode{*this} and +\tcode{x} becomes empty. +Pointers and references to the moved elements of \tcode{x} +now refer to those same elements but as members of \tcode{*this}. +Iterators referring to the moved elements continue to refer to their elements, +but they now behave as iterators into \tcode{*this}, not into \tcode{x}. \pnum -\complexity -Initializes exactly $N$ elements -from the results of dereferencing successive iterators of \tcode{rg}, -where $N$ is \tcode{ranges::distance(rg)}. -Performs no reallocations if \tcode{R} models -\tcode{ranges::\libconcept{forward_range}} or \tcode{ranges::\libconcept{sized_range}}; -otherwise, performs order $\log N$ reallocations and -order $N$ calls to the copy or move constructor of \tcode{T}. -\end{itemdescr} - -\rSec3[vector.capacity]{Capacity} - -\indexlibrarymember{capacity}{vector}% -\begin{itemdecl} -constexpr size_type capacity() const noexcept; -\end{itemdecl} +\throws +\tcode{length_error} if any of \tcode{x}'s active blocks +are not within the bounds of \exposid{current-limits}. -\begin{itemdescr} \pnum -\returns -The total number of elements that the vector can hold -without requiring reallocation. +\complexity +Linear in the sum of +all element blocks in \tcode{x} plus all element blocks in \tcode{*this}. \pnum -\complexity -Constant time. +\remarks +Reserved blocks in \tcode{x} are not transferred into \tcode{*this}. +If \tcode{addressof(x) == this} is \tcode{false}, +invalidates the past-the-end iterator for both \tcode{x} and \tcode{*this}. \end{itemdescr} -\indexlibrarymember{reserve}{vector}% +\indexlibrarymember{unique}{hive}% \begin{itemdecl} -constexpr void reserve(size_type n); +template> + size_type unique(BinaryPredicate binary_pred = BinaryPredicate()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{MoveInsertable} into \tcode{*this}. +\tcode{binary_pred} is an equivalence relation. \pnum \effects -A directive that informs a -\tcode{vector} -of a planned change in size, so that it can manage the storage allocation accordingly. -After -\tcode{reserve()}, -\tcode{capacity()} -is greater or equal to the argument of -\tcode{reserve} -if reallocation happens; and equal to the previous value of -\tcode{capacity()} -otherwise. -Reallocation happens at this point if and only if the current capacity is less than the -argument of -\tcode{reserve()}. If an exception is thrown -other than by the move constructor of a non-\oldconcept{CopyInsertable} type, -there are no effects. +Erases all but the first element +from every consecutive group of equivalent elements. +That is, for a nonempty \tcode{hive}, +erases all elements referred to by the iterator \tcode{i} +in the range \range{begin() + 1}{end()} +for which \tcode{binary_pred(*i, *(i - 1))} is \tcode{true}. + +\pnum +\returns +The number of elements erased. \pnum \throws -\tcode{length_error} if \tcode{n > -max_size()}. -\begin{footnote} -\tcode{reserve()} uses \tcode{Allocator::allocate()} which -can throw an appropriate exception. -\end{footnote} +Nothing unless an exception is thrown by the predicate. \pnum \complexity -It does not change the size of the sequence and takes at most linear -time in the size of the sequence. +If \tcode{empty()} is \tcode{false}, +exactly \tcode{size() - 1} applications of the corresponding predicate, +otherwise no applications of the predicate. \pnum \remarks -Reallocation invalidates all the references, pointers, and iterators -referring to the elements in the sequence, as well as the past-the-end iterator. -\begin{note} -If no reallocation happens, they remain valid. -\end{note} -No reallocation shall take place during insertions that happen -after a call to \tcode{reserve()} -until an insertion would make the size of the vector -greater than the value of \tcode{capacity()}. +Invalidates references, pointers, and iterators +referring to the erased elements. +If the last element in \tcode{*this} is erased, +also invalidates the past-the-end iterator. \end{itemdescr} -\indexlibrarymember{shrink_to_fit}{vector}% +\indexlibrarymember{sort}{hive}% \begin{itemdecl} -constexpr void shrink_to_fit(); +template> + void sort(Compare comp = Compare()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} is \oldconcept{MoveInsertable} into \tcode{*this}. +\tcode{T} is \oldconcept{MoveInsertable} into \tcode{hive}, +\oldconcept{MoveAssignable}, and \oldconcept{Swappable}. \pnum \effects -\tcode{shrink_to_fit} is a non-binding request to reduce -\tcode{capacity()} to \tcode{size()}. -\begin{note} -The request is non-binding to allow latitude for -implementation-specific optimizations. -\end{note} -It does not increase \tcode{capacity()}, but may reduce \tcode{capacity()} -by causing reallocation. -If an exception is thrown other than by the move constructor -of a non-\oldconcept{CopyInsertable} \tcode{T} there are no effects. +Sorts \tcode{*this} according to the \tcode{comp} function object. +If an exception is thrown, +the order of the elements in \tcode{*this} is unspecified. \pnum \complexity -If reallocation happens, -linear in the size of the sequence. +\bigoh{N \log N} comparisons, where $N$ is \tcode{size()}. \pnum \remarks -Reallocation invalidates all the references, pointers, and iterators -referring to the elements in the sequence as well as the past-the-end iterator. +May allocate. +References, pointers, and iterators referring to elements in \tcode{*this}, +as well as the past-the-end iterator, may be invalidated. \begin{note} -If no reallocation happens, they remain valid. +Not required to be stable\ref{algorithm.stable}. \end{note} \end{itemdescr} -\indexlibrarymember{swap}{vector}% +\indexlibrarymember{get_iterator}{hive}% \begin{itemdecl} -constexpr void swap(vector& x) - noexcept(allocator_traits::propagate_on_container_swap::value || - allocator_traits::is_always_equal::value); +iterator get_iterator(const_pointer p) noexcept; +const_iterator get_iterator(const_pointer p) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Exchanges the contents and -\tcode{capacity()} -of -\tcode{*this} -with that of \tcode{x}. +\expects +\tcode{p} points to an element in \tcode{*this}. + +\pnum +\returns +An \tcode{iterator} or \tcode{const_iterator} +pointing to the same element as \tcode{p}. \pnum \complexity -Constant time. +Linear in the number of active blocks in \tcode{*this}. \end{itemdescr} -\indexlibrarymember{resize}{vector}% +\rSec3[hive.erasure]{Erasure} + +\indexlibrarymember{erase}{hive}% \begin{itemdecl} -constexpr void resize(size_type sz); +template + typename hive::size_type + erase(hive& c, const U& value); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{T} is -\oldconcept{MoveInsertable} and \oldconcept{DefaultInsertable} into \tcode{*this}. - \pnum \effects -If \tcode{sz < size()}, erases the last \tcode{size() - sz} elements -from the sequence. Otherwise, -appends \tcode{sz - size()} default-inserted elements to the sequence. - -\pnum -\remarks -If an exception is thrown other than by the move constructor of a non-\oldconcept{CopyInsertable} -\tcode{T} there are no effects. +Equivalent to: +\begin{codeblock} +return erase_if(c, [&](auto& elem) { return elem == value; }); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{resize}{vector}% +\indexlibrarymember{erase_if}{hive}% \begin{itemdecl} -constexpr void resize(size_type sz, const T& c); +template + typename hive::size_type + erase_if(hive& c, Predicate pred); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{T} is -\oldconcept{CopyInsertable} into \tcode{*this}. - \pnum \effects -If \tcode{sz < size()}, erases the last \tcode{size() - sz} elements -from the sequence. Otherwise, -appends \tcode{sz - size()} copies of \tcode{c} to the sequence. - -\pnum -\remarks -If an exception is thrown there are no effects. -\end{itemdescr} - -\rSec3[vector.data]{Data} - -\indexlibrarymember{data}{vector}% -\begin{itemdecl} -constexpr T* data() noexcept; -constexpr const T* data() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A pointer such that \range{data()}{data() + size()} is a valid range. For a -non-empty vector, \tcode{data() == addressof(front())} is \keyword{true}. - -\pnum -\complexity -Constant time. +Equivalent to: +\begin{codeblock} +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +\end{codeblock} \end{itemdescr} -\rSec3[vector.modifiers]{Modifiers} - -\indexlibrarymember{insert}{vector}% -\begin{itemdecl} -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 - constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last); -template<@\exposconcept{container-compatible-range}@ R> - constexpr iterator insert_range(const_iterator position, R&& rg); -constexpr iterator insert(const_iterator position, initializer_list); - -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); -template<@\exposconcept{container-compatible-range}@ R> - constexpr void append_range(R&& rg); -\end{itemdecl} +\rSec2[list.syn]{Header \tcode{} synopsis} -\begin{itemdescr} -\pnum -\complexity -If reallocation happens, -linear in the number of elements of the resulting vector; -otherwise, -linear in the number of elements inserted plus the distance -to the end of the vector. +\indexheader{list}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} -\pnum -\remarks -Causes reallocation if the new size is greater than the old capacity. -Reallocation invalidates all the references, pointers, and iterators -referring to the elements in the sequence, as well as the past-the-end iterator. -If no reallocation happens, then -references, pointers, and iterators -before the insertion point remain valid -but those at or after the insertion point, -including the past-the-end iterator, -are invalidated. -If an exception is thrown other than by -the copy constructor, move constructor, -assignment operator, or move assignment operator of -\tcode{T} or by any \tcode{InputIterator} operation -there are no effects. -If an exception is thrown while inserting a single element at the end and -\tcode{T} is \oldconcept{CopyInsertable} or \tcode{is_nothrow_move_constructible_v} -is \tcode{true}, there are no effects. -Otherwise, if an exception is thrown by the move constructor of a non-\oldconcept{CopyInsertable} -\tcode{T}, the effects are unspecified. -\end{itemdescr} +namespace std { + // \ref{list}, class template \tcode{list} + template> class list; -\indexlibrarymember{erase}{vector}% -\begin{itemdecl} -constexpr iterator erase(const_iterator position); -constexpr iterator erase(const_iterator first, const_iterator last); -constexpr void pop_back(); -\end{itemdecl} + template + constexpr bool operator==(const list& x, const list& y); + template + constexpr @\placeholder{synth-three-way-result}@ operator<=>(const list& x, + @\itcorr@ const list& y); -\begin{itemdescr} -\pnum -\effects -Invalidates iterators and references at or after the point of the erase. + template + constexpr void swap(list& x, list& y) + noexcept(noexcept(x.swap(y))); -\pnum -\throws -Nothing unless an exception is thrown by the -assignment operator or move assignment operator of -\tcode{T}. + // \ref{list.erasure}, erasure + template + constexpr typename list::size_type + erase(list& c, const U& value); + template + constexpr typename list::size_type + erase_if(list& c, Predicate pred); -\pnum -\complexity -The destructor of \tcode{T} is called the number of times equal to the -number of the elements erased, but the assignment operator -of \tcode{T} is called the number of times equal to the number of -elements in the vector after the erased elements. -\end{itemdescr} + namespace pmr { + template + using list = std::list>; + } +} +\end{codeblock} -\rSec3[vector.erasure]{Erasure} +\rSec2[list]{Class template \tcode{list}} -\indexlibrarymember{erase}{vector}% -\begin{itemdecl} -template - constexpr typename vector::size_type - erase(vector& c, const U& value); -\end{itemdecl} +\rSec3[list.overview]{Overview} -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto it = remove(c.begin(), c.end(), value); -auto r = distance(it, c.end()); -c.erase(it, c.end()); -return r; -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{erase_if}{vector}% -\begin{itemdecl} -template - constexpr typename vector::size_type - erase_if(vector& c, Predicate pred); -\end{itemdecl} +\indexlibraryglobal{list}% +A +\tcode{list} +is a sequence container that supports +bidirectional iterators and allows constant time insert and erase +operations anywhere within the sequence, with storage management handled +automatically. Unlike vectors\iref{vector} and deques\iref{deque}, +fast random access to list elements is not supported, but many +algorithms only need sequential access anyway. -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto it = remove_if(c.begin(), c.end(), pred); -auto r = distance(it, c.end()); -c.erase(it, c.end()); -return r; -\end{codeblock} -\end{itemdescr} - -\rSec2[vector.bool]{Specialization of \tcode{vector} for \tcode{bool}} - -\rSec3[vector.bool.pspc]{Partial class template specialization \tcode{vector}} +A \tcode{list} meets all of the requirements +of a container\iref{container.reqmts}, +of a reversible container\iref{container.rev.reqmts}, +of an allocator-aware container\iref{container.alloc.reqmts}, and +of a sequence container, +including most of the optional sequence container +requirements\iref{sequence.reqmts}. +The exceptions are the +\tcode{operator[]} +and +\tcode{at} +member functions, which are not provided. +\begin{footnote} +These member functions +are only provided by containers whose iterators +are random access iterators. +\end{footnote} +Descriptions are provided here only for operations on +\tcode{list} +that are not described in one of these tables +or for operations where there is additional semantic information. \pnum -\indexlibraryglobal{vector}% -To optimize space allocation, a partial specialization of \tcode{vector} for -\tcode{bool} elements is provided: +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\ref{iterator.requirements.general}. + \begin{codeblock} namespace std { - template - class vector { + template> + class list { public: // types - using value_type = bool; + using value_type = T; using allocator_type = Allocator; - using pointer = @\impdefx{type of \tcode{vector::pointer}}@; - using const_pointer = @\impdefx{type of \tcode{vector::const_pointer}}@; - using const_reference = bool; - using size_type = @\impdefx{type of \tcode{vector::size_type}}@; // see \ref{container.requirements} - using difference_type = @\impdefx{type of \tcode{vector::difference_type}}@; // see \ref{container.requirements} - using iterator = @\impdefx{type of \tcode{vector::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{vector::const_iterator}}@; // see \ref{container.requirements} + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = @\impdefx{type of \tcode{list::size_type}}@; // see \ref{container.requirements} + using difference_type = @\impdefx{type of \tcode{list::difference_type}}@; // see \ref{container.requirements} + using iterator = @\impdefx{type of \tcode{list::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{list::const_iterator}}@; // see \ref{container.requirements} using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - // bit reference - class @\libmember{reference}{vector}@ { - friend class vector; - constexpr reference() noexcept; - - public: - constexpr reference(const reference&) = default; - constexpr ~reference(); - constexpr operator bool() const noexcept; - constexpr reference& operator=(bool x) noexcept; - constexpr reference& operator=(const reference& x) noexcept; - constexpr const reference& operator=(bool x) const noexcept; - constexpr void flip() noexcept; // flips the bit - }; - - // construct/copy/destroy - 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 bool& value, const Allocator& = Allocator()); + // \ref{list.cons}, construct/copy/destroy + constexpr list() : list(Allocator()) { } + constexpr explicit list(const Allocator&); + constexpr explicit list(size_type n, const Allocator& = Allocator()); + constexpr list(size_type n, const T& value, const Allocator& = Allocator()); template - constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); - template<@\exposconcept{container-compatible-range}@ R> - constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); - constexpr vector(const vector& x); - constexpr vector(vector&& x) noexcept; - constexpr vector(const vector&, const type_identity_t&); - constexpr vector(vector&&, const type_identity_t&); - 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); - constexpr vector& operator=(initializer_list); + constexpr list(InputIterator first, InputIterator last, const Allocator& = Allocator()); + template<@\exposconcept{container-compatible-range}@ R> + constexpr list(from_range_t, R&& rg, const Allocator& = Allocator()); + constexpr list(const list& x); + constexpr list(list&& x); + constexpr list(const list&, const type_identity_t&); + constexpr list(list&&, const type_identity_t&); + constexpr list(initializer_list, const Allocator& = Allocator()); + constexpr ~list(); + constexpr list& operator=(const list& x); + constexpr list& operator=(list&& x) + noexcept(allocator_traits::is_always_equal::value); + constexpr list& operator=(initializer_list); template constexpr void assign(InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> + template<@\exposconcept{container-compatible-range}@ R> constexpr void assign_range(R&& rg); - constexpr void assign(size_type n, const bool& t); - constexpr void assign(initializer_list); + constexpr void assign(size_type n, const T& t); + constexpr void assign(initializer_list); constexpr allocator_type get_allocator() const noexcept; // iterators @@ -9281,191 +9129,2271 @@ constexpr const_reverse_iterator crbegin() const noexcept; constexpr const_reverse_iterator crend() const noexcept; - // capacity - [[nodiscard]] constexpr bool empty() const noexcept; + // \ref{list.capacity}, capacity + 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(); + constexpr void resize(size_type sz); + constexpr void resize(size_type sz, const T& c); // element access - 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 + // \ref{list.modifiers}, modifiers + template constexpr reference emplace_front(Args&&... args); template constexpr reference emplace_back(Args&&... args); - constexpr void push_back(const bool& x); - template<@\exposconcept{container-compatible-range}@ R> + constexpr void push_front(const T& x); + constexpr void push_front(T&& x); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void prepend_range(R&& rg); + constexpr void pop_front(); + constexpr void push_back(const T& x); + constexpr void push_back(T&& x); + template<@\exposconcept{container-compatible-range}@ R> constexpr void append_range(R&& rg); 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); + 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 constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> + template<@\exposconcept{container-compatible-range}@ R> constexpr iterator insert_range(const_iterator position, R&& rg); - constexpr iterator insert(const_iterator position, initializer_list il); + 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); - static constexpr void swap(reference x, reference y) noexcept; - constexpr void flip() noexcept; // flips all bits - constexpr void clear() noexcept; + constexpr iterator erase(const_iterator position, const_iterator last); + constexpr void swap(list&) noexcept(allocator_traits::is_always_equal::value); + constexpr void clear() noexcept; + + // \ref{list.ops}, list operations + constexpr void splice(const_iterator position, list& x); + constexpr void splice(const_iterator position, list&& x); + constexpr void splice(const_iterator position, list& x, const_iterator i); + constexpr void splice(const_iterator position, list&& x, const_iterator i); + constexpr void splice(const_iterator position, list& x, + const_iterator first, const_iterator last); + constexpr void splice(const_iterator position, list&& x, + const_iterator first, const_iterator last); + + constexpr size_type remove(const T& value); + template constexpr size_type remove_if(Predicate pred); + + constexpr size_type unique(); + template + constexpr size_type unique(BinaryPredicate binary_pred); + + constexpr void merge(list& x); + constexpr void merge(list&& x); + template constexpr void merge(list& x, Compare comp); + template constexpr void merge(list&& x, Compare comp); + + constexpr void sort(); + template constexpr void sort(Compare comp); + + constexpr void reverse() noexcept; }; -} -\end{codeblock}% -\pnum -Unless described below, all operations have the same requirements and -semantics as the primary \tcode{vector} template, except that operations -dealing with the \tcode{bool} value type map to bit values in the -container storage and -\tcode{allocator_traits::construct}\iref{allocator.traits.members} -is not used to construct these values. + template>> + list(InputIterator, InputIterator, Allocator = Allocator()) + -> list<@\placeholder{iter-value-type}@, Allocator>; -\pnum -There is no requirement that the data be stored as a contiguous allocation -of \tcode{bool} values. A space-optimized representation of bits is -recommended instead. + template>> + list(from_range_t, R&&, Allocator = Allocator()) + -> list, Allocator>; +} +\end{codeblock} \pnum -\tcode{reference} -is a class that simulates the behavior of references of a single bit in -\tcode{vector}. The conversion function returns \tcode{true} -when the bit is set, and \tcode{false} otherwise. The assignment operators -set the bit when the argument is (convertible to) \tcode{true} and -clear it otherwise. \tcode{flip} reverses the state of the bit. +An incomplete type \tcode{T} may be used when instantiating \tcode{list} +if the allocator meets the +allocator completeness requirements\iref{allocator.requirements.completeness}. +\tcode{T} shall be complete before any member of the resulting specialization +of \tcode{list} is referenced. -\indexlibrarymember{flip}{vector}% +\rSec3[list.cons]{Constructors, copy, and assignment} + +\indexlibraryctor{list}% \begin{itemdecl} -constexpr void flip() noexcept; +constexpr explicit list(const Allocator&); \end{itemdecl} \begin{itemdescr} \pnum \effects -Replaces each element in the container with its complement. +Constructs an empty list, using the specified allocator. + +\pnum +\complexity +Constant. \end{itemdescr} -\indexlibrarymember{swap}{vector}% +\indexlibraryctor{list}% \begin{itemdecl} -static constexpr void swap(reference x, reference y) noexcept; +constexpr explicit list(size_type n, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Exchanges the contents of \tcode{x} and \tcode{y} as if by: +\expects +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{list}. -\begin{codeblock} -bool b = x; -x = y; -y = b; -\end{codeblock} +\pnum +\effects +Constructs a \tcode{list} with +\tcode{n} default-inserted elements using the specified allocator. +\pnum +\complexity +Linear in +\tcode{n}. \end{itemdescr} +\indexlibraryctor{list}% \begin{itemdecl} -template struct hash>; +constexpr list(size_type n, const T& value, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum -The specialization is enabled\iref{unord.hash}. +\expects +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{list}. + +\pnum +\effects +Constructs a +\tcode{list} +with +\tcode{n} +copies of +\tcode{value}, +using the specified allocator. + +\pnum +\complexity +Linear in +\tcode{n}. \end{itemdescr} -\indexlibrary{is-vector-bool-reference@\exposid{is-vector-bool-reference}}% +\indexlibraryctor{list}% \begin{itemdecl} -template - constexpr bool @\exposid{is-vector-bool-reference}@ = @\seebelow@; +template + constexpr list(InputIterator first, InputIterator last, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum -The expression -\tcode{\exposid{is-vector-bool-reference}} is \tcode{true} -if \tcode{T} denotes the type \tcode{vector::\linebreak{}reference} -for some type \tcode{Alloc} and -\tcode{vector} is not a program-defined specialization. +\effects +Constructs a +\tcode{list} +equal to the range +\range{first}{last}. + +\pnum +\complexity +Linear in +\tcode{distance(first, last)}. \end{itemdescr} -\rSec3[vector.bool.fmt]{Formatter specialization for \tcode{vector}} +\indexlibraryctor{list}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr list(from_range_t, R&& rg, const Allocator& = Allocator()); +\end{itemdecl} -\indexlibraryglobal{formatter}% -\begin{codeblock} -namespace std { - template - requires @\exposid{is-vector-bool-reference}@ - struct formatter { - private: - formatter @\exposid{underlying_}@; // \expos +\begin{itemdescr} +\pnum +\effects +Constructs a \tcode{list} object with the elements of the range \tcode{rg}. - public: - template - constexpr typename ParseContext::iterator - parse(ParseContext& ctx); +\pnum +\complexity +Linear in \tcode{ranges::distance(rg)}. +\end{itemdescr} - template - typename FormatContext::iterator - format(const T& ref, FormatContext& ctx) const; - }; -} -\end{codeblock} +\rSec3[list.capacity]{Capacity} -\indexlibrarymember{parse}{formatter}% +\indexlibrarymember{resize}{list}% \begin{itemdecl} -template - constexpr typename ParseContext::iterator - parse(ParseContext& ctx); +constexpr void resize(size_type sz); \end{itemdecl} \begin{itemdescr} \pnum -Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +\expects +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{list}. + +\pnum +\effects +If \tcode{size() < sz}, +appends \tcode{sz - size()} default-inserted elements to the +sequence. +If \tcode{sz <= size()}, equivalent to: + +\begin{codeblock} +list::iterator it = begin(); +advance(it, sz); +erase(it, end()); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{format}{formatter}% +\indexlibrarymember{resize}{list}% \begin{itemdecl} -template - typename FormatContext::iterator - format(const T& ref, FormatContext& ctx) const; +constexpr void resize(size_type sz, const T& c); \end{itemdecl} \begin{itemdescr} \pnum -Equivalent to: \tcode{return \exposid{underlying_}.format(ref, ctx);} +\expects +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{list}. + +\pnum +\effects +As if by: +\begin{codeblock} +if (sz > size()) + insert(end(), sz-size(), c); +else if (sz < size()) { + iterator i = begin(); + advance(i, sz); + erase(i, end()); +} +else + ; // do nothing +\end{codeblock} \end{itemdescr} -\rSec1[associative]{Associative containers} +\rSec3[list.modifiers]{Modifiers} + +\indexlibrarymember{insert}{list}% +\begin{itemdecl} +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 + constexpr iterator insert(const_iterator position, + InputIterator first, InputIterator last); +template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator position, R&& rg); +constexpr iterator insert(const_iterator position, initializer_list); -\rSec2[associative.general]{In general} +template constexpr reference emplace_front(Args&&... args); +template constexpr reference emplace_back(Args&&... args); +template constexpr iterator emplace(const_iterator position, Args&&... args); +constexpr void push_front(const T& x); +constexpr void push_front(T&& x); +template<@\exposconcept{container-compatible-range}@ R> + constexpr void prepend_range(R&& rg); +constexpr void push_back(const T& x); +constexpr void push_back(T&& x); +template<@\exposconcept{container-compatible-range}@ R> + constexpr void append_range(R&& rg); +\end{itemdecl} +\begin{itemdescr} \pnum -The header \libheader{map} defines the class templates \tcode{map} and -\tcode{multimap}; the header \libheader{set} defines the class templates -\tcode{set} and \tcode{multiset}. +\complexity +Insertion of a single element into a list takes constant time and +exactly one call to a constructor of +\tcode{T}. Insertion of multiple elements into a list is linear in the +number of elements inserted, and the number of calls to the copy +constructor or move constructor of \tcode{T} is exactly equal +to the number of elements inserted. \pnum -The following exposition-only alias templates may appear in deduction guides for associative containers: -\begin{codeblock} -template - using @\placeholder{iter-value-type}@ = - typename iterator_traits::value_type; // \expos -template - using @\placeholder{iter-key-type}@ = remove_const_t< +\remarks +Does not affect the validity of iterators and references. +If an exception is thrown, there are no effects. +\end{itemdescr} + +\indexlibrarymember{erase}{list}% +\begin{itemdecl} +constexpr iterator erase(const_iterator position); +constexpr iterator erase(const_iterator first, const_iterator last); +constexpr void pop_front(); +constexpr void pop_back(); +constexpr void clear() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Invalidates only the iterators and references to the erased elements. + +\pnum +\throws +Nothing. + +\pnum +\complexity +Erasing a single element is a constant time operation with a single call to the destructor of +\tcode{T}. +Erasing a range in a list is linear time in the +size of the range and the number of calls to the destructor of type +\tcode{T} +is exactly equal to the size of the range. +\end{itemdescr} + +\rSec3[list.ops]{Operations} + +\pnum +Since lists allow fast insertion and erasing from the middle of a list, certain +operations are provided specifically for them. +\begin{footnote} +As specified +in~\ref{allocator.requirements}, the requirements in this Clause apply only to +lists whose allocators compare equal. +\end{footnote} +In this subclause, +arguments for a template parameter +named \tcode{Predicate} or \tcode{BinaryPredicate} +shall meet the corresponding requirements in \ref{algorithms.requirements}. +The semantics of \tcode{i + n} and \tcode{i - n}, +where \tcode{i} is an iterator into the list and \tcode{n} is an integer, +are the same as those of \tcode{next(i, n)} and \tcode{prev(i, n)}, +respectively. +For \tcode{merge} and \tcode{sort}, +the definitions and requirements in \ref{alg.sorting} apply. + +\pnum +\tcode{list} provides three splice operations that destructively move elements from one list to +another. The behavior of splice operations is undefined if \tcode{get_allocator() != +x.get_allocator()}. + +\indexlibrarymember{splice}{list}% +\begin{itemdecl} +constexpr void splice(const_iterator position, list& x); +constexpr void splice(const_iterator position, list&& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{addressof(x) != this} is \tcode{true}. + +\pnum +\effects +Inserts the contents of +\tcode{x} +before +\tcode{position} +and +\tcode{x} +becomes empty. +Pointers and references to the moved elements of +\tcode{x} +now refer to those same elements but as members of +\tcode{*this}. +Iterators referring to the moved elements will continue to refer to their +elements, but they now behave as iterators into +\tcode{*this}, +not into +\tcode{x}. + +\pnum +\throws +Nothing. + +\pnum +\complexity +Constant time. +\end{itemdescr} + +\indexlibrarymember{splice}{list}% +\begin{itemdecl} +constexpr void splice(const_iterator position, list& x, const_iterator i); +constexpr void splice(const_iterator position, list&& x, const_iterator i); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{i} is a valid dereferenceable iterator of \tcode{x}. + +\pnum +\effects +Inserts an element pointed to by +\tcode{i} +from list +\tcode{x} +before \tcode{position} and removes the element from +\tcode{x}. +The result is unchanged if +\tcode{position == i} +or +\tcode{position == ++i}. +Pointers and references to +\tcode{*i} +continue to refer to this same element but as a member of +\tcode{*this}. +Iterators +to +\tcode{*i} +(including +\tcode{i} +itself) continue to refer to the same element, but now behave as iterators into +\tcode{*this}, +not into +\tcode{x}. + +\pnum +\throws +Nothing. + +\pnum +\complexity +Constant time. +\end{itemdescr} + +\indexlibrarymember{splice}{list}% +\begin{itemdecl} +constexpr void splice(const_iterator position, list& x, + const_iterator first, const_iterator last); +constexpr void splice(const_iterator position, list&& x, + const_iterator first, const_iterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\range{first}{last} is a valid range in \tcode{x}. +\tcode{position} is not an iterator in the range \range{first}{last}. + +\pnum +\effects +Inserts elements in the range +\range{first}{last} +before +\tcode{position} +and removes the elements from +\tcode{x}. +Pointers and references to the moved elements of +\tcode{x} +now refer to those same elements but as members of +\tcode{*this}. +Iterators referring to the moved elements will continue to refer to their +elements, but they now behave as iterators into +\tcode{*this}, +not into +\tcode{x}. + +\pnum +\throws +Nothing. + +\pnum +\complexity +Constant time if +\tcode{addressof(x) == this}; +otherwise, linear time. +\end{itemdescr} + +\indexlibrarymember{remove}{list}% +\begin{itemdecl} +constexpr size_type remove(const T& value); +template constexpr size_type remove_if(Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Erases all the elements in the list referred to by a list iterator \tcode{i} for which the +following conditions hold: \tcode{*i == value}, \tcode{pred(*i) != false}. +Invalidates only the iterators and references to the erased elements. + +\pnum +\returns +The number of elements erased. + +\pnum +\throws +Nothing unless an exception is thrown by +\tcode{*i == value} +or +\tcode{pred(*i) != false}. + +\pnum +\complexity +Exactly +\tcode{size()} +applications of the corresponding predicate. + +\pnum +\remarks +Stable\iref{algorithm.stable}. +\end{itemdescr} + +\indexlibrarymember{unique}{list}% +\begin{itemdecl} +constexpr size_type unique(); +template constexpr size_type unique(BinaryPredicate binary_pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{binary_pred} be \tcode{equal_to<>\{\}} for the first overload. + +\pnum +\expects +\tcode{binary_pred} is an equivalence relation. + +\pnum +\effects +Erases all but the first element from every +consecutive group of equivalent elements. +That is, for a nonempty list, erases all elements referred to +by the iterator \tcode{i} in the range \range{begin() + 1}{end()} +for which \tcode{binary_pred(*i, *(i - 1))} is \tcode{true}. +Invalidates only the iterators and references to the erased elements. + +\pnum +\returns +The number of elements erased. + +\pnum +\throws +Nothing unless an exception is thrown by the predicate. + +\pnum +\complexity +If \tcode{empty()} is \tcode{false}, +exactly \tcode{size() - 1} applications of the corresponding predicate, +otherwise no applications of the predicate. +\end{itemdescr} + +\indexlibrarymember{merge}{list}% +\begin{itemdecl} +constexpr void merge(list& x); +constexpr void merge(list&& x); +template constexpr void merge(list& x, Compare comp); +template constexpr void merge(list&& x, Compare comp); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{comp} be \tcode{less<>{}} for the first two overloads. + +\pnum +\expects +\tcode{*this} and \tcode{x} are both sorted +with respect to the comparator \tcode{comp}, and +\tcode{get_allocator() == x.get_allocator()} is \tcode{true}. + +\pnum +\effects +If \tcode{addressof(x) == this}, there are no effects. +Otherwise, merges +the two sorted ranges \range{begin()}{end()} and \range{x.begin()}{x.end()}. +The result is a range +that is sorted with respect to the comparator \tcode{comp}. +Pointers and references to the moved elements of \tcode{x} now refer to those same elements +but as members of \tcode{*this}. Iterators referring to the moved elements will continue to +refer to their elements, but they now behave as iterators into \tcode{*this}, not into +\tcode{x}. + +\pnum +\complexity +At most \tcode{size() + x.size() - 1} comparisons +if \tcode{addressof(x) != this}; +otherwise, no comparisons are performed. + +\pnum +\remarks +Stable\iref{algorithm.stable}. +If \tcode{addressof(x) != this}, \tcode{x} is empty after the merge. +No elements are copied by this operation. +If an exception is thrown other than by a comparison, there are no effects. +\end{itemdescr} + +\indexlibrarymember{reverse}{list}% +\begin{itemdecl} +constexpr void reverse() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Reverses the order of the elements in the list. +Does not affect the validity of iterators and references. + +\pnum +\complexity +Linear time. +\end{itemdescr} + +\indexlibrarymember{sort}{list}% +\begin{itemdecl} +void sort(); +template void sort(Compare comp); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Sorts the list according to the \tcode{operator<} or a \tcode{Compare} function object. +If an exception is thrown, +the order of the elements in \tcode{*this} is unspecified. +Does not affect the validity of iterators and references. + +\pnum +\complexity +Approximately +$N \log N$ +comparisons, where $N$ is \tcode{size()}. + +\pnum +\remarks +Stable\iref{algorithm.stable}. +\end{itemdescr} + +\rSec3[list.erasure]{Erasure} + +\indexlibrarymember{erase}{list}% +\begin{itemdecl} +template + typename list::size_type + constexpr erase(list& c, const U& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return erase_if(c, [&](const auto& elem) -> bool { return elem == value; }); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{erase_if}{list}% +\begin{itemdecl} +template + typename list::size_type + constexpr erase_if(list& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return c.remove_if(pred);} +\end{itemdescr} + +\rSec2[vector.syn]{Header \tcode{} synopsis} + +\indexheader{vector}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{vector}, class template \tcode{vector} + template> class vector; + + template + constexpr bool operator==(const vector& x, const vector& y); + template + constexpr @\placeholder{synth-three-way-result}@ operator<=>(const vector& x, + @\itcorr@ const vector& y); + + template + constexpr void swap(vector& x, vector& y) + noexcept(noexcept(x.swap(y))); + + // \ref{vector.erasure}, erasure + template + constexpr typename vector::size_type + erase(vector& c, const U& value); + template + constexpr typename vector::size_type + erase_if(vector& c, Predicate pred); + + namespace pmr { + template + using vector = std::vector>; + } + + // \ref{vector.bool}, specialization of \tcode{vector} for \tcode{bool} + // \ref{vector.bool.pspc}, partial class template specialization \tcode{vector} + template + class vector; + + template + constexpr bool @\exposid{is-vector-bool-reference}@ = @\seebelow@; // \expos + + // hash support + template struct hash; + template struct hash>; + + // \ref{vector.bool.fmt}, formatter specialization for \tcode{vector} + template requires @\exposid{is-vector-bool-reference}@ + struct formatter; +} +\end{codeblock} + +\rSec2[vector]{Class template \tcode{vector}} + +\rSec3[vector.overview]{Overview} + +\pnum +\indexlibraryglobal{vector}% +A +\tcode{vector} +is a sequence container that supports +(amortized) constant time insert and erase operations at the end; +insert and erase in the middle take linear time. +Storage management is handled automatically, though hints can be given +to improve efficiency. + +\pnum +A \tcode{vector} meets all of the requirements +of a container\iref{container.reqmts}, +of a reversible container\iref{container.rev.reqmts}, +of an allocator-aware container\iref{container.alloc.reqmts}, +of a sequence container, including most of the optional sequence container +requirements\iref{sequence.reqmts}, +and, for an element type other than \tcode{bool}, +of a contiguous container\iref{container.reqmts}. +The exceptions are the +\tcode{push_front}, \tcode{prepend_range}, \tcode{pop_front}, and \tcode{emplace_front} member functions, which are not +provided. Descriptions are provided here only for operations on \tcode{vector} +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> + class vector { + public: + // types + using value_type = T; + using allocator_type = Allocator; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = @\impdefx{type of \tcode{vector::size_type}}@; // see \ref{container.requirements} + using difference_type = @\impdefx{type of \tcode{vector::difference_type}}@; // see \ref{container.requirements} + using iterator = @\impdefx{type of \tcode{vector::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{vector::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // \ref{vector.cons}, construct/copy/destroy + 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 + constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); + template<@\exposconcept{container-compatible-range}@ R> + constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); + constexpr vector(const vector& x); + constexpr vector(vector&&) noexcept; + constexpr vector(const vector&, const type_identity_t&); + constexpr vector(vector&&, const type_identity_t&); + 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); + constexpr vector& operator=(initializer_list); + template + constexpr void assign(InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void assign_range(R&& rg); + constexpr void assign(size_type n, const T& u); + constexpr void assign(initializer_list); + constexpr allocator_type get_allocator() const noexcept; + + // iterators + 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; + + 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 + 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 + constexpr reference operator[](size_type n); + constexpr const_reference operator[](size_type n) const; + constexpr reference at(size_type n); + constexpr const_reference at(size_type n) const; + constexpr reference front(); + constexpr const_reference front() const; + constexpr reference back(); + constexpr const_reference back() const; + + // \ref{vector.data}, data access + constexpr T* data() noexcept; + constexpr const T* data() const noexcept; + + // \ref{vector.modifiers}, modifiers + template constexpr reference emplace_back(Args&&... args); + constexpr void push_back(const T& x); + constexpr void push_back(T&& x); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void append_range(R&& rg); + 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 + constexpr iterator insert(const_iterator position, + InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator position, R&& rg); + 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); + constexpr void clear() noexcept; + }; + + template>> + vector(InputIterator, InputIterator, Allocator = Allocator()) + -> vector<@\placeholder{iter-value-type}@, Allocator>; + + template>> + vector(from_range_t, R&&, Allocator = Allocator()) + -> vector, Allocator>; +} +\end{codeblock}% +\indexlibrarymember{vector}{operator==}% +\indexlibrarymember{vector}{operator<} + +\pnum +An incomplete type \tcode{T} may be used when instantiating \tcode{vector} +if the allocator meets the +allocator completeness requirements\iref{allocator.requirements.completeness}. +\tcode{T} shall be complete before any member of the resulting specialization +of \tcode{vector} is referenced. + +\rSec3[vector.cons]{Constructors} + +\indexlibraryctor{vector} +\begin{itemdecl} +constexpr explicit vector(const Allocator&) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs an empty \tcode{vector}, using the +specified allocator. + +\pnum +\complexity +Constant. +\end{itemdescr} + +\indexlibraryctor{vector} +\begin{itemdecl} +constexpr explicit vector(size_type n, const Allocator& = Allocator()); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{vector}. + +\pnum +\effects +Constructs a \tcode{vector} with \tcode{n} +default-inserted elements using the specified allocator. + +\pnum +\complexity +Linear in \tcode{n}. +\end{itemdescr} + +\indexlibraryctor{vector} +\begin{itemdecl} +constexpr vector(size_type n, const T& value, + const Allocator& = Allocator()); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is +\oldconcept{CopyInsertable} into \tcode{vector}. + +\pnum +\effects +Constructs a \tcode{vector} with \tcode{n} +copies of \tcode{value}, using the specified allocator. + +\pnum +\complexity +Linear in \tcode{n}. +\end{itemdescr} + +\indexlibraryctor{vector} +\begin{itemdecl} +template + constexpr vector(InputIterator first, InputIterator last, + const Allocator& = Allocator()); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs a \tcode{vector} equal to the +range \range{first}{last}, using the specified allocator. + +\pnum +\complexity +Makes only $N$ +calls to the copy constructor of +\tcode{T} +(where $N$ +is the distance between +\tcode{first} +and +\tcode{last}) +and no reallocations if +\tcode{InputIterator} meets the \oldconcept{ForwardIterator} requirements. +It makes order +$N$ +calls to the copy constructor of +\tcode{T} +and order +$\log N$ +reallocations if they are just input iterators. +\end{itemdescr} + +\indexlibraryctor{vector}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs a \tcode{vector} object with the elements of the range \tcode{rg}, +using the specified allocator. + +\pnum +\complexity +Initializes exactly $N$ elements +from the results of dereferencing successive iterators of \tcode{rg}, +where $N$ is \tcode{ranges::distance(rg)}. + +\pnum +Performs no reallocations if: +\begin{itemize} +\item +\tcode{R} models \tcode{ranges::\libconcept{approximately_sized_range}}, and +\tcode{ranges::distance(rg) <= ranges::re\-serve_hint(rg)} is \tcode{true}, or +\item +\tcode{R} models \tcode{ranges::\libconcept{forward_range}} and +\tcode{R} does not model \tcode{ranges::\libconcept{approximately_sized_range}}. +\end{itemize} +Otherwise, performs order $\log N$ reallocations and +order $N$ calls to the copy or move constructor of \tcode{T}. +\end{itemdescr} + +\rSec3[vector.capacity]{Capacity} + +\indexlibrarymember{capacity}{vector}% +\begin{itemdecl} +constexpr size_type capacity() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The total number of elements that the vector can hold +without requiring reallocation. + +\pnum +\complexity +Constant time. +\end{itemdescr} + +\indexlibrarymember{reserve}{vector}% +\begin{itemdecl} +constexpr void reserve(size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{MoveInsertable} into \tcode{vector}. + +\pnum +\effects +A directive that informs a +\tcode{vector} +of a planned change in size, so that it can manage the storage allocation accordingly. +After +\tcode{reserve()}, +\tcode{capacity()} +is greater or equal to the argument of +\tcode{reserve} +if reallocation happens; and equal to the previous value of +\tcode{capacity()} +otherwise. +Reallocation happens at this point if and only if the current capacity is less than the +argument of +\tcode{reserve()}. If an exception is thrown +other than by the move constructor of a non-\oldconcept{CopyInsertable} type, +there are no effects. + +\pnum +\throws +\tcode{length_error} if \tcode{n > +max_size()}. +\begin{footnote} +\tcode{reserve()} uses \tcode{Allocator::allocate()} which +can throw an appropriate exception. +\end{footnote} + +\pnum +\complexity +It does not change the size of the sequence and takes at most linear +time in the size of the sequence. + +\pnum +\remarks +Reallocation invalidates all the references, pointers, and iterators +referring to the elements in the sequence, as well as the past-the-end iterator. +\begin{note} +If no reallocation happens, they remain valid. +\end{note} +No reallocation shall take place during insertions that happen +after a call to \tcode{reserve()} +until an insertion would make the size of the vector +greater than the value of \tcode{capacity()}. +\end{itemdescr} + +\indexlibrarymember{shrink_to_fit}{vector}% +\begin{itemdecl} +constexpr void shrink_to_fit(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{MoveInsertable} into \tcode{vector}. + +\pnum +\effects +\tcode{shrink_to_fit} is a non-binding request to reduce +\tcode{capacity()} to \tcode{size()}. +\begin{note} +The request is non-binding to allow latitude for +implementation-specific optimizations. +\end{note} +It does not increase \tcode{capacity()}, but may reduce \tcode{capacity()} +by causing reallocation. +If an exception is thrown other than by the move constructor +of a non-\oldconcept{CopyInsertable} \tcode{T}, there are no effects. + +\pnum +\complexity +If reallocation happens, +linear in the size of the sequence. + +\pnum +\remarks +Reallocation invalidates all the references, pointers, and iterators +referring to the elements in the sequence as well as the past-the-end iterator. +\begin{note} +If no reallocation happens, they remain valid. +\end{note} +\end{itemdescr} + +\indexlibrarymember{swap}{vector}% +\begin{itemdecl} +constexpr void swap(vector& x) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Exchanges the contents and +\tcode{capacity()} +of +\tcode{*this} +with that of \tcode{x}. + +\pnum +\complexity +Constant time. +\end{itemdescr} + +\indexlibrarymember{resize}{vector}% +\begin{itemdecl} +constexpr void resize(size_type sz); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is +\oldconcept{MoveInsertable} and \oldconcept{DefaultInsertable} into \tcode{vector}. + +\pnum +\effects +If \tcode{sz < size()}, erases the last \tcode{size() - sz} elements +from the sequence. Otherwise, +appends \tcode{sz - size()} default-inserted elements to the sequence. + +\pnum +\remarks +If an exception is thrown other than by the move constructor of a non-\oldconcept{CopyInsertable} +\tcode{T}, there are no effects. +\end{itemdescr} + +\indexlibrarymember{resize}{vector}% +\begin{itemdecl} +constexpr void resize(size_type sz, const T& c); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is +\oldconcept{CopyInsertable} into \tcode{vector}. + +\pnum +\effects +If \tcode{sz < size()}, erases the last \tcode{size() - sz} elements +from the sequence. Otherwise, +appends \tcode{sz - size()} copies of \tcode{c} to the sequence. + +\pnum +\remarks +If an exception is thrown, there are no effects. +\end{itemdescr} + +\rSec3[vector.data]{Data} + +\indexlibrarymember{data}{vector}% +\begin{itemdecl} +constexpr T* data() noexcept; +constexpr const T* data() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A pointer such that \range{data()}{data() + size()} is a valid range. For a +non-empty vector, \tcode{data() == addressof(front())} is \keyword{true}. + +\pnum +\complexity +Constant time. +\end{itemdescr} + +\rSec3[vector.modifiers]{Modifiers} + +\indexlibrarymember{insert}{vector}% +\begin{itemdecl} +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 + constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last); +template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator position, R&& rg); +constexpr iterator insert(const_iterator position, initializer_list); + +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); +template<@\exposconcept{container-compatible-range}@ R> + constexpr void append_range(R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\complexity +If reallocation happens, +linear in the number of elements of the resulting vector; +otherwise, +linear in the number of elements inserted plus the distance +to the end of the vector. + +\pnum +\remarks +Causes reallocation if the new size is greater than the old capacity. +Reallocation invalidates all the references, pointers, and iterators +referring to the elements in the sequence, as well as the past-the-end iterator. +If no reallocation happens, then +references, pointers, and iterators +before the insertion point remain valid +but those at or after the insertion point, +including the past-the-end iterator, +are invalidated. +If an exception is thrown other than by +the copy constructor, move constructor, +assignment operator, or move assignment operator of +\tcode{T} or by any \tcode{InputIterator} operation, +there are no effects. +If an exception is thrown while inserting a single element at the end and +\tcode{T} is \oldconcept{CopyInsertable} or \tcode{is_nothrow_move_constructible_v} +is \tcode{true}, there are no effects. +Otherwise, if an exception is thrown by the move constructor of a non-\oldconcept{CopyInsertable} +\tcode{T}, the effects are unspecified. + +\pnum +For the declarations taking a range \tcode{R}, +performs at most one reallocation if: +\begin{itemize} +\item +\tcode{R} models \tcode{ranges::\libconcept{approximately_sized_range}} and +\tcode{ranges::distance(rg) <= ranges::re\-serve_hint(rg)} is \tcode{true}, or +\item +\tcode{R} models \tcode{ranges::\libconcept{forward_range}} and +\tcode{R} does not model \tcode{ranges::\libconcept{approximately_sized_range}}. +\end{itemize} +For the declarations taking a pair of \tcode{InputIterator}, +performs at most one reallocation if +\tcode{InputItera\-tor} meets the \oldconcept{ForwardIterator} requirements. +\end{itemdescr} + +\indexlibrarymember{erase}{vector}% +\begin{itemdecl} +constexpr iterator erase(const_iterator position); +constexpr iterator erase(const_iterator first, const_iterator last); +constexpr void pop_back(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Invalidates iterators and references at or after the point of the erase. + +\pnum +\throws +Nothing unless an exception is thrown by the +assignment operator or move assignment operator of +\tcode{T}. + +\pnum +\complexity +The destructor of \tcode{T} is called the number of times equal to the +number of the elements erased, but the assignment operator +of \tcode{T} is called the number of times equal to the number of +elements in the vector after the erased elements. +\end{itemdescr} + +\rSec3[vector.erasure]{Erasure} + +\indexlibrarymember{erase}{vector}% +\begin{itemdecl} +template + constexpr typename vector::size_type + erase(vector& c, const U& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto it = remove(c.begin(), c.end(), value); +auto r = distance(it, c.end()); +c.erase(it, c.end()); +return r; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{erase_if}{vector}% +\begin{itemdecl} +template + constexpr typename vector::size_type + erase_if(vector& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto it = remove_if(c.begin(), c.end(), pred); +auto r = distance(it, c.end()); +c.erase(it, c.end()); +return r; +\end{codeblock} +\end{itemdescr} + +\rSec2[vector.bool]{Specialization of \tcode{vector} for \tcode{bool}} + +\rSec3[vector.bool.pspc]{Partial class template specialization \tcode{vector}} + +\pnum +\indexlibraryglobal{vector}% +To optimize space allocation, a partial specialization of \tcode{vector} for +\tcode{bool} elements is provided: +\begin{codeblock} +namespace std { + template + class vector { + public: + // types + using value_type = bool; + using allocator_type = Allocator; + using pointer = @\impdefx{type of \tcode{vector::pointer}}@; + using const_pointer = @\impdefx{type of \tcode{vector::const_pointer}}@; + using const_reference = bool; + using size_type = @\impdefx{type of \tcode{vector::size_type}}@; // see \ref{container.requirements} + using difference_type = @\impdefx{type of \tcode{vector::difference_type}}@; // see \ref{container.requirements} + using iterator = @\impdefx{type of \tcode{vector::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{vector::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // bit reference + class @\libmember{reference}{vector}@ { + public: + constexpr reference(const reference&) = default; + constexpr ~reference(); + constexpr operator bool() const noexcept; + constexpr reference& operator=(bool x) noexcept; + constexpr reference& operator=(const reference& x) noexcept; + constexpr const reference& operator=(bool x) const noexcept; + constexpr void flip() noexcept; // flips the bit + }; + + // construct/copy/destroy + 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 bool& value, const Allocator& = Allocator()); + template + constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); + template<@\exposconcept{container-compatible-range}@ R> + constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); + constexpr vector(const vector& x); + constexpr vector(vector&& x) noexcept; + constexpr vector(const vector&, const type_identity_t&); + constexpr vector(vector&&, const type_identity_t&); + 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); + constexpr vector& operator=(initializer_list); + template + constexpr void assign(InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void assign_range(R&& rg); + constexpr void assign(size_type n, const bool& t); + constexpr void assign(initializer_list); + constexpr allocator_type get_allocator() const noexcept; + + // iterators + 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; + + 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 + 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 + constexpr reference operator[](size_type n); + constexpr const_reference operator[](size_type n) const; + constexpr reference at(size_type n); + constexpr const_reference at(size_type n) const; + constexpr reference front(); + constexpr const_reference front() const; + constexpr reference back(); + constexpr const_reference back() const; + + // modifiers + template constexpr reference emplace_back(Args&&... args); + constexpr void push_back(const bool& x); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void append_range(R&& rg); + 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 + constexpr iterator insert(const_iterator position, + InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator position, R&& rg); + 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); + static constexpr void swap(reference x, reference y) noexcept; + constexpr void flip() noexcept; // flips all bits + constexpr void clear() noexcept; + }; +} +\end{codeblock}% + +\pnum +Unless described below, all operations have the same requirements and +semantics as the primary \tcode{vector} template, except that operations +dealing with the \tcode{bool} value type map to bit values in the +container storage and +\tcode{allocator_traits::construct}\iref{allocator.traits.members} +is not used to construct these values. + +\pnum +There is no requirement that the data be stored as a contiguous allocation +of \tcode{bool} values. A space-optimized representation of bits is +recommended instead. + +\pnum +\tcode{reference} +is a class that simulates the behavior of references of a single bit in +\tcode{vector}. The conversion function returns \tcode{true} +when the bit is set, and \tcode{false} otherwise. The assignment operators +set the bit when the argument is (convertible to) \tcode{true} and +clear it otherwise. \tcode{flip} reverses the state of the bit. + +\indexlibrarymember{flip}{vector}% +\begin{itemdecl} +constexpr void flip() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Replaces each element in the container with its complement. +\end{itemdescr} + +\indexlibrarymember{swap}{vector}% +\begin{itemdecl} +static constexpr void swap(reference x, reference y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Exchanges the contents of \tcode{x} and \tcode{y} as if by: + +\begin{codeblock} +bool b = x; +x = y; +y = b; +\end{codeblock} + +\end{itemdescr} + +\begin{itemdecl} +template struct hash>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The specialization is enabled\iref{unord.hash}. +\end{itemdescr} + +\indexlibrary{is-vector-bool-reference@\exposid{is-vector-bool-reference}}% +\begin{itemdecl} +template + constexpr bool @\exposid{is-vector-bool-reference}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The expression +\tcode{\exposid{is-vector-bool-reference}} is \tcode{true} +if \tcode{T} denotes the type \tcode{vector::\linebreak{}reference} +for some type \tcode{Alloc} and +\tcode{vector} is not a program-defined specialization. +\end{itemdescr} + +\rSec3[vector.bool.fmt]{Formatter specialization for \tcode{vector}} + +\indexlibraryglobal{formatter}% +\begin{codeblock} +namespace std { + template + requires @\exposid{is-vector-bool-reference}@ + struct formatter { + private: + formatter @\exposid{underlying_}@; // \expos + + public: + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(const T& ref, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\indexlibrarymember{parse}{formatter}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +\end{itemdescr} + +\indexlibrarymember{format}{formatter}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(const T& ref, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Equivalent to: \tcode{return \exposid{underlying_}.format(ref, ctx);} +\end{itemdescr} + +\rSec2[inplace.vector.syn]{Header \tcode{} synopsis} + +\indexheader{inplace_vector}% +\begin{codeblock} +// mostly freestanding +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{inplace.vector}, class template \tcode{inplace_vector} + template class inplace_vector; // partially freestanding + + // \ref{inplace.vector.erasure}, erasure + template + constexpr typename inplace_vector::size_type + erase(inplace_vector& c, const U& value); + template + constexpr typename inplace_vector::size_type + erase_if(inplace_vector& c, Predicate pred); +} +\end{codeblock} + +\rSec2[inplace.vector]{Class template \tcode{inplace_vector}} + +\rSec3[inplace.vector.overview]{Overview} + +\pnum +\indexlibraryglobal{inplace_vector}% +An \tcode{inplace_vector} is a contiguous container. +Its capacity is fixed and +its elements are stored within the \tcode{inplace_vector} object itself. + +\pnum +An \tcode{inplace_vector} meets all of the requirements +of a container\iref{container.reqmts}, +of a reversible container\iref{container.rev.reqmts}, +of a contiguous container, and +of a sequence container, +including most of the optional sequence container requirements\iref{sequence.reqmts}. +The exceptions are the +\tcode{push_front}, +\tcode{prepend_range}, +\tcode{pop_front}, and +\tcode{emplace_front} +member functions, which are not provided. +Descriptions are provided here only +for operations on \tcode{inplace_vector} that +are not described in one of these tables or +for operations where there is additional semantic information. + +\pnum +For any \tcode{N}, +\tcode{inplace_vector::iterator} and +\tcode{inplace_vector::const_iterator} +meet the constexpr iterator requirements. + +\pnum +Any member function of \tcode{inplace_vector} that +would cause the size to exceed \tcode{N} +throws an exception of type \tcode{bad_alloc}. + +\pnum +Let \tcode{IV} denote a specialization of \tcode{inplace_vector}. +If \tcode{N} is zero, then +\tcode{IV} is trivially copyable and empty, and +\tcode{std::is_trivially_default_constructible_v} is \tcode{true}. +Otherwise: +\begin{itemize} +\item +If \tcode{is_trivially_copy_constructible_v} is \tcode{true}, then +\tcode{IV} has a trivial copy constructor. +\item +If \tcode{is_trivially_move_constructible_v} is \tcode{true}, then +\tcode{IV} has a trivial move constructor. +\item +If \tcode{is_trivially_destructible_v} is \tcode{true}, then: + \begin{itemize} + \item + \tcode{IV} has a trivial destructor. + \item + If +\begin{codeblock} + is_trivially_copy_constructible_v && is_trivially_copy_assignable_v +\end{codeblock} + is \tcode{true}, then + \tcode{IV} has a trivial copy assignment operator. + \item + If +\begin{codeblock} + is_trivially_move_constructible_v && is_trivially_move_assignable_v +\end{codeblock} + is \tcode{true}, then + \tcode{IV} has a trivial move assignment operator. + \end{itemize} +\end{itemize} + +\begin{codeblock} +namespace std { + template + class inplace_vector { + public: + // types: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = @\impdefx{type of \tcode{inplace_vector::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{inplace_vector::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // \ref{inplace.vector.cons}, construct/copy/destroy + constexpr inplace_vector() noexcept; + constexpr explicit inplace_vector(size_type n); // freestanding-deleted + constexpr inplace_vector(size_type n, const T& value); // freestanding-deleted + template + constexpr inplace_vector(InputIterator first, InputIterator last); // freestanding-deleted + template<@\exposconcept{container-compatible-range}@ R> + constexpr inplace_vector(from_range_t, R&& rg); // freestanding-deleted + constexpr inplace_vector(const inplace_vector&); + constexpr inplace_vector(inplace_vector&&) + noexcept(N == 0 || is_nothrow_move_constructible_v); + constexpr inplace_vector(initializer_list il); // freestanding-deleted + constexpr ~inplace_vector(); + constexpr inplace_vector& operator=(const inplace_vector& other); + constexpr inplace_vector& operator=(inplace_vector&& other) + noexcept(N == 0 || (is_nothrow_move_assignable_v && + is_nothrow_move_constructible_v)); + constexpr inplace_vector& operator=(initializer_list); // freestanding-deleted + template + constexpr void assign(InputIterator first, InputIterator last); // freestanding-deleted + template<@\exposconcept{container-compatible-range}@ R> + constexpr void assign_range(R&& rg); // freestanding-deleted + constexpr void assign(size_type n, const T& u); // freestanding-deleted + constexpr void assign(initializer_list il); // freestanding-deleted + + // iterators + 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; + + 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{inplace.vector.capacity}, size/capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + static constexpr size_type max_size() noexcept; + static constexpr size_type capacity() noexcept; + constexpr void resize(size_type sz); // freestanding-deleted + constexpr void resize(size_type sz, const T& c); // freestanding-deleted + static constexpr void reserve(size_type n); // freestanding-deleted + static constexpr void shrink_to_fit() noexcept; + + // element access + constexpr reference operator[](size_type n); + constexpr const_reference operator[](size_type n) const; + constexpr reference at(size_type n); // freestanding-deleted + constexpr const_reference at(size_type n) const; // freestanding-deleted + constexpr reference front(); + constexpr const_reference front() const; + constexpr reference back(); + constexpr const_reference back() const; + + // \ref{inplace.vector.data}, data access + constexpr T* data() noexcept; + constexpr const T* data() const noexcept; + + // \ref{inplace.vector.modifiers}, modifiers + template + constexpr reference emplace_back(Args&&... args); // freestanding-deleted + constexpr reference push_back(const T& x); // freestanding-deleted + constexpr reference push_back(T&& x); // freestanding-deleted + template<@\exposconcept{container-compatible-range}@ R> + constexpr void append_range(R&& rg); // freestanding-deleted + constexpr void pop_back(); + + template + constexpr pointer try_emplace_back(Args&&... args); + constexpr pointer try_push_back(const T& x); + constexpr pointer try_push_back(T&& x); + template<@\exposconcept{container-compatible-range}@ R> + constexpr ranges::borrowed_iterator_t try_append_range(R&& rg); + + template + constexpr reference unchecked_emplace_back(Args&&... args); + constexpr reference unchecked_push_back(const T& x); + constexpr reference unchecked_push_back(T&& x); + + template + constexpr iterator emplace(const_iterator position, Args&&... args); // freestanding-deleted + constexpr iterator insert(const_iterator position, const T& x); // freestanding-deleted + constexpr iterator insert(const_iterator position, T&& x); // freestanding-deleted + constexpr iterator insert(const_iterator position, size_type n, // freestanding-deleted + const T& x); + template + constexpr iterator insert(const_iterator position, // freestanding-deleted + InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator position, R&& rg); // freestanding-deleted + constexpr iterator insert(const_iterator position, // freestanding-deleted + initializer_list il); + constexpr iterator erase(const_iterator position); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(inplace_vector& x) + noexcept(N == 0 || (is_nothrow_swappable_v && + is_nothrow_move_constructible_v)); + constexpr void clear() noexcept; + + constexpr friend bool operator==(const inplace_vector& x, + const inplace_vector& y); + constexpr friend @\exposid{synth-three-way-result}@ + operator<=>(const inplace_vector& x, const inplace_vector& y); + constexpr friend void swap(inplace_vector& x, inplace_vector& y) + noexcept(N == 0 || (is_nothrow_swappable_v && + is_nothrow_move_constructible_v)) + { x.swap(y); } + }; +} +\end{codeblock} + +\rSec3[inplace.vector.cons]{Constructors} + +\indexlibraryctor{inplace_vector} +\begin{itemdecl} +constexpr explicit inplace_vector(size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{inplace_vector}. + +\pnum +\effects +Constructs an \tcode{inplace_vector} with \tcode{n} default-inserted elements. + +\pnum +\complexity +Linear in \tcode{n}. +\end{itemdescr} + +\indexlibraryctor{inplace_vector} +\begin{itemdecl} +constexpr inplace_vector(size_type n, const T& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{inplace_vector}. + +\pnum +\effects +Constructs an \tcode{inplace_vector} with \tcode{n} copies of \tcode{value}. + +\pnum +\complexity +Linear in \tcode{n}. +\end{itemdescr} + +\indexlibraryctor{inplace_vector} +\begin{itemdecl} +template + constexpr inplace_vector(InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs an \tcode{inplace_vector} equal to the range \range{first}{last}. + +\pnum +\complexity +Linear in \tcode{distance(first, last)}. +\end{itemdescr} + +\indexlibraryctor{inplace_vector} +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr inplace_vector(from_range_t, R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs an \tcode{inplace_vector} with +the elements of the range \tcode{rg}. + +\pnum +\complexity +Linear in \tcode{ranges::distance(rg)}. +\end{itemdescr} + +\rSec3[inplace.vector.capacity]{Size and capacity} + +\indexlibrarymember{capacity}{inplace_vector}% +\indexlibrarymember{max_size}{inplace_vector}% +\begin{itemdecl} +static constexpr size_type capacity() noexcept; +static constexpr size_type max_size() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{N}. +\end{itemdescr} + +\indexlibrarymember{resize}{inplace_vector}% +\begin{itemdecl} +constexpr void resize(size_type sz); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{DefaultInsertable} into \tcode{inplace_vector}. + +\pnum +\effects +%FIXME: Should "is \tcode{true}" be appended here? +If \tcode{sz < size()}, +erases the last \tcode{size() - sz} elements from the sequence. +Otherwise, +appends \tcode{sz - size()} default-inserted elements to the sequence. + +\pnum +\remarks +If an exception is thrown, there are no effects on \tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{resize}{inplace_vector}% +\begin{itemdecl} +constexpr void resize(size_type sz, const T& c); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} is \oldconcept{CopyInsertable} into \tcode{inplace_vector}. + +\pnum +\effects +%FIXME: Should "is \tcode{true}" be appended here? +If \tcode{sz < size()}, +erases the last \tcode{size() - sz} elements from the sequence. +Otherwise, +appends \tcode{sz - size()} copies of \tcode{c} to the sequence. + +\pnum +\remarks +If an exception is thrown, there are no effects on \tcode{*this}. +\end{itemdescr} + +\rSec3[inplace.vector.data]{Data} + +\indexlibrarymember{data}{inplace_vector}% +\begin{itemdecl} +constexpr T* data() noexcept; +constexpr const T* data() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A pointer such that \range{data()}{data() + size()} is a valid range. +For a non-empty \tcode{inplace_vector}, +\tcode{data() == addressof(front())} is \tcode{true}. + +\pnum +\complexity +Constant time. +\end{itemdescr} + +\rSec3[inplace.vector.modifiers]{Modifiers} + +\indexlibrarymember{insert}{inplace_vector}% +\indexlibrarymember{insert_range}{inplace_vector}% +\indexlibrarymember{emplace}{inplace_vector}% +\indexlibrarymember{append_range}{inplace_vector}% +\begin{itemdecl} +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 + constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last); +template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator position, R&& rg); +constexpr iterator insert(const_iterator position, initializer_list il); + +template + constexpr iterator emplace(const_iterator position, Args&&... args); +template<@\exposconcept{container-compatible-range}@ R> + constexpr void append_range(R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $n$ be the value of \tcode{size()} before this call for +the \tcode{append_range} overload, and +\tcode{distance(begin, position)} otherwise. + +\pnum +\complexity +Linear in the number of elements inserted plus +the distance to the end of the vector. + +\pnum +\remarks +If an exception is thrown other than by the +copy constructor, +move constructor, +assignment operator, or +move assignment operator +of \tcode{T} or by +any \tcode{InputIterator} operation, +there are no effects. +Otherwise, +if an exception is thrown, then +$\tcode{size()} \ge n$ and +elements in the range \tcode{begin() + \range{0}{$n$}} are not modified. +\end{itemdescr} + +\indexlibrarymember{push_back}{inplace_vector}% +\indexlibrarymember{emplace_back}{inplace_vector}% +\begin{itemdecl} +constexpr reference push_back(const T& x); +constexpr reference push_back(T&& x); +template + constexpr reference emplace_back(Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{back()}. + +\pnum +\throws +\tcode{bad_alloc} or +any exception thrown by the initialization of the inserted element. + +\pnum +\complexity +Constant. + +\pnum +\remarks +If an exception is thrown, there are no effects on \tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{try_emplace_back}{inplace_vector}% +\indexlibrarymember{try_push_back}{inplace_vector}% +\begin{itemdecl} +template + constexpr pointer try_emplace_back(Args&&... args); +constexpr pointer try_push_back(const T& x); +constexpr pointer try_push_back(T&& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{vals} denote a pack: +\begin{itemize} +\item \tcode{std::forward(args)...} for the first overload, +\item \tcode{x} for the second overload, +\item \tcode{std::move(x)} for the third overload. +\end{itemize} + +\pnum +\expects +\tcode{value_type} is \oldconcept{EmplaceConstructible} +into \tcode{inplace_vector} from \tcode{vals...}. + +\pnum +\effects +If \tcode{size() < capacity()} is \tcode{true}, +appends an object of type \tcode{T} +direct-non-list-initialized with \tcode{vals...}. +Otherwise, there are no effects. + +\pnum +\returns +\keyword{nullptr} if \tcode{size() == capacity()} is \tcode{true}, +otherwise \tcode{addressof(back())}. + +\pnum +\throws +Nothing unless an exception is thrown by the initialization of the inserted element. + +\pnum +\complexity +Constant. + +\pnum +\remarks +If an exception is thrown, there are no effects on \tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{try_append_range}{inplace_vector}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr ranges::borrowed_iterator_t try_append_range(R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{value_type} is \oldconcept{EmplaceConstructible} +into \tcode{inplace_vector} from\\\tcode{*ranges::begin(rg)}. + +\pnum +\effects +Appends copies of initial elements in \tcode{rg} before \tcode{end()}, +until all elements are inserted or \tcode{size() == capacity()} is \tcode{true}. +Each iterator in the range \tcode{rg} is dereferenced at most once. + +\pnum +\returns +An iterator pointing to the first element of \tcode{rg} +that was not inserted into \tcode{*this}, +or \tcode{ranges::end(rg)} if no such element exists. + +\pnum +\complexity +Linear in the number of elements inserted. + +\pnum +\remarks +Let $n$ be the value of \tcode{size()} prior to this call. +If an exception is thrown after the insertion of $k$ elements, then +\tcode{size()} equals $n + k$, +elements in the range \tcode{begin() + \range{0}{$n$}} are not modified, and +elements in the range \tcode{begin() + \range{$n$}{$n + k$}} correspond to +the inserted elements. +\end{itemdescr} + +\indexlibrarymember{unchecked_emplace_back}{inplace_vector}% +\begin{itemdecl} +template + constexpr reference unchecked_emplace_back(Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{size() < capacity()} is \tcode{true}. + +\pnum +\effects +Equivalent to: +\tcode{return *try_emplace_back(std::forward(args)...);} +\end{itemdescr} + +\indexlibrarymember{unchecked_push_back}{inplace_vector}% +\begin{itemdecl} +constexpr reference unchecked_push_back(const T& x); +constexpr reference unchecked_push_back(T&& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{size() < capacity()} is \tcode{true}. + +\pnum +\effects +Equivalent to: +\tcode{return *try_push_back(std::forward(x));} +\end{itemdescr} + +\indexlibrarymember{reserve}{inplace_vector}% +\begin{itemdecl} +static constexpr void reserve(size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +None. + +\pnum +\throws +\tcode{bad_alloc} if \tcode{n > capacity()} is \tcode{true}. +\end{itemdescr} + +\indexlibrarymember{shrink_to_fit}{inplace_vector}% +\begin{itemdecl} +static constexpr void shrink_to_fit() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +None. +\end{itemdescr} + +\indexlibrarymember{erase}{inplace_vector}% +\indexlibrarymember{pop_back}{inplace_vector}% +\begin{itemdecl} +constexpr iterator erase(const_iterator position); +constexpr iterator erase(const_iterator first, const_iterator last); +constexpr void pop_back(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Invalidates iterators and references at or after the point of the erase. + +\pnum +\throws +Nothing unless an exception is thrown by +the assignment operator or move assignment operator of \tcode{T}. + +\pnum +\complexity +The destructor of \tcode{T} is called the number of times +equal to the number of the elements erased, but +the assignment operator of \tcode{T} is called the number of times +equal to the number of elements after the erased elements. +\end{itemdescr} + +\rSec3[inplace.vector.erasure]{Erasure} + +\indexlibrarymember{erase}{inplace_vector}% +\begin{itemdecl} +template + constexpr size_t erase(inplace_vector& c, const U& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto it = remove(c.begin(), c.end(), value); +auto r = distance(it, c.end()); +c.erase(it, c.end()); +return r; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{erase_if}{inplace_vector}% +\begin{itemdecl} +template + constexpr size_t erase_if(inplace_vector& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto it = remove_if(c.begin(), c.end(), pred); +auto r = distance(it, c.end()); +c.erase(it, c.end()); +return r; +\end{codeblock} +\end{itemdescr} + +\rSec1[associative]{Associative containers} + +\rSec2[associative.general]{General} + +\pnum +The header \libheaderrefx{map}{associative.map.syn} defines the class templates +\tcode{map} and \tcode{multimap}; +the header \libheaderrefx{set}{associative.set.syn} defines the class templates +\tcode{set} and \tcode{multiset}. + +\pnum +The following exposition-only alias templates may appear in deduction guides for associative containers: +\begin{codeblock} +template + using @\placeholder{iter-value-type}@ = + typename iterator_traits::value_type; // \expos +template + using @\placeholder{iter-key-type}@ = remove_const_t< tuple_element_t<0, @\exposid{iter-value-type}@>>; // \expos template using @\placeholder{iter-mapped-type}@ = @@ -9499,21 +11427,21 @@ class map; template - bool operator==(const map& x, - const map& y); + constexpr bool operator==(const map& x, + const map& y); template - @\placeholder{synth-three-way-result}@> + constexpr @\placeholder{synth-three-way-result}@> operator<=>(const map& x, const map& y); template - void swap(map& x, - map& y) + constexpr void swap(map& x, + map& y) noexcept(noexcept(x.swap(y))); // \ref{map.erasure}, erasure for \tcode{map} template - typename map::size_type + constexpr typename map::size_type erase_if(map& c, Predicate pred); // \ref{multimap}, class template \tcode{multimap} @@ -9522,21 +11450,21 @@ class multimap; template - bool operator==(const multimap& x, - const multimap& y); + constexpr bool operator==(const multimap& x, + const multimap& y); template - @\placeholder{synth-three-way-result}@> + constexpr @\placeholder{synth-three-way-result}@> operator<=>(const multimap& x, const multimap& y); template - void swap(multimap& x, + constexpr void swap(multimap& x, multimap& y) noexcept(noexcept(x.swap(y))); // \ref{multimap.erasure}, erasure for \tcode{multimap} template - typename multimap::size_type + constexpr typename multimap::size_type erase_if(multimap& c, Predicate pred); namespace pmr { @@ -9551,66 +11479,6 @@ } \end{codeblock} -\rSec2[associative.set.syn]{Header \tcode{} synopsis}% - -\indexheader{set}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} - -namespace std { - // \ref{set}, class template \tcode{set} - template, class Allocator = allocator> - class set; - - template - bool operator==(const set& x, - const set& y); - template - @\placeholder{synth-three-way-result}@ operator<=>(const set& x, - @\itcorr@ const set& y); - - template - void swap(set& x, - set& y) - noexcept(noexcept(x.swap(y))); - - // \ref{set.erasure}, erasure for \tcode{set} - template - typename set::size_type - erase_if(set& c, Predicate pred); - - // \ref{multiset}, class template \tcode{multiset} - template, class Allocator = allocator> - class multiset; - - template - bool operator==(const multiset& x, - const multiset& y); - template - @\placeholder{synth-three-way-result}@ operator<=>(const multiset& x, - @\itcorr@ const multiset& y); - - template - void swap(multiset& x, - multiset& y) - noexcept(noexcept(x.swap(y))); - - // \ref{multiset.erasure}, erasure for \tcode{multiset} - template - typename multiset::size_type - erase_if(multiset& c, Predicate pred); - - namespace pmr { - template> - using set = std::set>; - - template> - using multiset = std::multiset>; - } -} -\end{codeblock} - \rSec2[map]{Class template \tcode{map}} \rSec3[map.overview]{Overview} @@ -9626,7 +11494,7 @@ A \tcode{map} meets all of the requirements of a container\iref{container.reqmts}, of a reversible container\iref{container.rev.reqmts}, -of an allocator-aware container\iref{container.alloc.reqmts}. and +of an allocator-aware container\iref{container.alloc.reqmts}, and of an associative container\iref{associative.reqmts}. A \tcode{map} @@ -9655,6 +11523,10 @@ that are not described in one of those 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}. + \indexlibrarymember{comp}{map::value_compare}% \indexlibrarymember{operator()}{map::value_compare}% \begin{codeblock} @@ -9683,177 +11555,177 @@ using insert_return_type = @\placeholdernc{insert-return-type}@; class value_compare { - friend class map; protected: Compare comp; - value_compare(Compare c) : comp(c) {} + constexpr value_compare(Compare c) : comp(c) {} public: - bool operator()(const value_type& x, const value_type& y) const { + constexpr bool operator()(const value_type& x, const value_type& y) const { return comp(x.first, y.first); } }; // \ref{map.cons}, construct/copy/destroy - map() : map(Compare()) { } - explicit map(const Compare& comp, const Allocator& = Allocator()); + constexpr map() : map(Compare()) { } + constexpr explicit map(const Compare& comp, const Allocator& = Allocator()); template - map(InputIterator first, InputIterator last, - const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr map(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); template<@\exposconcept{container-compatible-range}@ R> - map(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); - map(const map& x); - map(map&& x); + constexpr map(from_range_t, R&& rg, const Compare& comp = Compare(), + const Allocator& = Allocator()); + constexpr map(const map& x); + constexpr map(map&& x); explicit map(const Allocator&); - map(const map&, const type_identity_t&); - map(map&&, const type_identity_t&); - map(initializer_list, - const Compare& = Compare(), - const Allocator& = Allocator()); + constexpr map(const map&, const type_identity_t&); + constexpr map(map&&, const type_identity_t&); + constexpr map(initializer_list, const Compare& = Compare(), + const Allocator& = Allocator()); template - map(InputIterator first, InputIterator last, const Allocator& a) + constexpr map(InputIterator first, InputIterator last, const Allocator& a) : map(first, last, Compare(), a) { } template<@\exposconcept{container-compatible-range}@ R> - map(from_range_t, R&& rg, const Allocator& a)) + constexpr map(from_range_t, R&& rg, const Allocator& a)) : map(from_range, std::forward(rg), Compare(), a) { } - map(initializer_list il, const Allocator& a) + constexpr map(initializer_list il, const Allocator& a) : map(il, Compare(), a) { } - ~map(); - map& operator=(const map& x); - map& operator=(map&& x) + constexpr ~map(); + constexpr map& operator=(const map& x); + constexpr map& operator=(map&& x) noexcept(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v); - map& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr map& operator=(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; + 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; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // \ref{map.access}, element access - mapped_type& operator[](const key_type& x); - mapped_type& operator[](key_type&& x); - template mapped_type& operator[](K&& x); - mapped_type& at(const key_type& x); - const mapped_type& at(const key_type& x) const; - template mapped_type& at(const K& x); - template const mapped_type& at(const K& x) const; + constexpr mapped_type& operator[](const key_type& x); + constexpr mapped_type& operator[](key_type&& x); + template constexpr mapped_type& operator[](K&& x); + constexpr mapped_type& at(const key_type& x); + constexpr const mapped_type& at(const key_type& x) const; + template constexpr mapped_type& at(const K& x); + template constexpr const mapped_type& at(const K& x) const; // \ref{map.modifiers}, modifiers - template pair emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - pair insert(const value_type& x); - pair insert(value_type&& x); - template pair insert(P&& x); - iterator insert(const_iterator position, const value_type& x); - iterator insert(const_iterator position, value_type&& x); + template constexpr pair emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr pair insert(const value_type& x); + constexpr pair insert(value_type&& x); + template constexpr pair insert(P&& x); + constexpr iterator insert(const_iterator position, const value_type& x); + constexpr iterator insert(const_iterator position, value_type&& x); template - iterator insert(const_iterator position, P&&); + constexpr iterator insert(const_iterator position, P&&); template - void insert(InputIterator first, InputIterator last); + constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); - node_type extract(const_iterator position); - node_type extract(const key_type& x); - template node_type extract(K&& x); - insert_return_type insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); + template constexpr node_type extract(K&& x); + constexpr insert_return_type insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); template - pair try_emplace(const key_type& k, Args&&... args); + constexpr pair try_emplace(const key_type& k, Args&&... args); template - pair try_emplace(key_type&& k, Args&&... args); + constexpr pair try_emplace(key_type&& k, Args&&... args); template - pair try_emplace(K&& k, Args&&... args); + constexpr pair try_emplace(K&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template - iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); template - pair insert_or_assign(const key_type& k, M&& obj); + constexpr pair insert_or_assign(const key_type& k, M&& obj); template - pair insert_or_assign(key_type&& k, M&& obj); + constexpr pair insert_or_assign(key_type&& k, M&& obj); template - pair insert_or_assign(K&& k, M&& obj); + constexpr pair insert_or_assign(K&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); - - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(map&) + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(map&) noexcept(allocator_traits::is_always_equal::value && is_nothrow_swappable_v); - void clear() noexcept; + constexpr void clear() noexcept; template - void merge(map& source); + constexpr void merge(map& source); template - void merge(map&& source); + constexpr void merge(map&& source); template - void merge(multimap& source); + constexpr void merge(multimap& source); template - void merge(multimap&& source); + constexpr void merge(multimap&& source); // observers - key_compare key_comp() const; - value_compare value_comp() const; + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; // map operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; - size_type count(const key_type& x) const; - template size_type count(const K& x) const; + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; - bool contains(const key_type& x) const; - template bool contains(const K& x) const; + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; template - pair equal_range(const K& x); + constexpr pair equal_range(const K& x); template - pair equal_range(const K& x) const; + constexpr pair equal_range(const K& x) const; }; template>, @@ -9892,7 +11764,7 @@ \indexlibraryctor{map}% \begin{itemdecl} -explicit map(const Compare& comp, const Allocator& = Allocator()); +constexpr explicit map(const Compare& comp, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -9910,8 +11782,8 @@ \indexlibraryctor{map}% \begin{itemdecl} template - map(InputIterator first, InputIterator last, - const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr map(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -9935,7 +11807,8 @@ \indexlibraryctor{map}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - map(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr map(from_range_t, R&& rg, const Compare& comp = Compare(), + const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -9955,7 +11828,7 @@ \indexlibrary{\idxcode{operator[]}!\idxcode{map}}% \begin{itemdecl} -mapped_type& operator[](const key_type& x); +constexpr mapped_type& operator[](const key_type& x); \end{itemdecl} \begin{itemdescr} @@ -9966,7 +11839,7 @@ \indexlibrary{\idxcode{operator[]}!\idxcode{map}}% \begin{itemdecl} -mapped_type& operator[](key_type&& x); +constexpr mapped_type& operator[](key_type&& x); \end{itemdecl} \begin{itemdescr} @@ -9977,7 +11850,7 @@ \indexlibrary{\idxcode{operator[]}!\idxcode{map}}% \begin{itemdecl} -template mapped_type& operator[](K&& x); +template constexpr mapped_type& operator[](K&& x); \end{itemdecl} \begin{itemdescr} @@ -9993,8 +11866,8 @@ \indexlibrarymember{at}{map}% \begin{itemdecl} -mapped_type& at(const key_type& x); -const mapped_type& at(const key_type& x) const; +constexpr mapped_type& at(const key_type& x); +constexpr const mapped_type& at(const key_type& x) const; \end{itemdecl} \begin{itemdescr} @@ -10014,8 +11887,8 @@ \indexlibrarymember{at}{map}% \begin{itemdecl} -template mapped_type& at(const K& x); -template const mapped_type& at(const K& x) const; +template constexpr mapped_type& at(const K& x); +template constexpr const mapped_type& at(const K& x) const; \end{itemdecl} \begin{itemdescr} @@ -10047,9 +11920,9 @@ \indexlibrarymember{insert}{map}% \begin{itemdecl} template - pair insert(P&& x); + constexpr pair insert(P&& x); template - iterator insert(const_iterator position, P&& x); + constexpr iterator insert(const_iterator position, P&& x); \end{itemdecl} \begin{itemdescr} @@ -10067,9 +11940,9 @@ \indexlibrarymember{try_emplace}{map}% \begin{itemdecl} template - pair try_emplace(const key_type& k, Args&&... args); + constexpr pair try_emplace(const key_type& k, Args&&... args); template - iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -10105,9 +11978,9 @@ \indexlibrarymember{try_emplace}{map}% \begin{itemdecl} template - pair try_emplace(key_type&& k, Args&&... args); + constexpr pair try_emplace(key_type&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -10143,9 +12016,9 @@ \indexlibrarymember{try_emplace}{map}% \begin{itemdecl} template - pair try_emplace(K&& k, Args&&... args); + constexpr pair try_emplace(K&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -10192,9 +12065,9 @@ \indexlibrarymember{insert_or_assign}{map}% \begin{itemdecl} template - pair insert_or_assign(const key_type& k, M&& obj); + constexpr pair insert_or_assign(const key_type& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); \end{itemdecl} \begin{itemdescr} @@ -10232,9 +12105,9 @@ \indexlibrarymember{insert_or_assign}{map}% \begin{itemdecl} template - pair insert_or_assign(key_type&& k, M&& obj); + constexpr pair insert_or_assign(key_type&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); \end{itemdecl} \begin{itemdescr} @@ -10272,9 +12145,9 @@ \indexlibrarymember{insert_or_assign}{map}% \begin{itemdecl} template - pair insert_or_assign(K&& k, M&& obj); + constexpr pair insert_or_assign(K&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); \end{itemdecl} \begin{itemdescr} @@ -10323,7 +12196,7 @@ \begin{itemdecl} template typename map::size_type - erase_if(map& c, Predicate pred); + constexpr erase_if(map& c, Predicate pred); \end{itemdecl} \begin{itemdescr} @@ -10393,6 +12266,10 @@ that are not described in one of those 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}. + \indexlibrarymember{comp}{multimap::value_compare}% \indexlibrarymember{operator()}{multimap::value_compare}% \begin{codeblock} @@ -10420,144 +12297,142 @@ using node_type = @\unspec@; class value_compare { - friend class multimap; protected: Compare comp; - value_compare(Compare c) : comp(c) { } + constexpr value_compare(Compare c) : comp(c) { } public: - bool operator()(const value_type& x, const value_type& y) const { + constexpr bool operator()(const value_type& x, const value_type& y) const { return comp(x.first, y.first); } }; // \ref{multimap.cons}, construct/copy/destroy - multimap() : multimap(Compare()) { } - explicit multimap(const Compare& comp, const Allocator& = Allocator()); + constexpr multimap() : multimap(Compare()) { } + constexpr explicit multimap(const Compare& comp, const Allocator& = Allocator()); template - multimap(InputIterator first, InputIterator last, - const Compare& comp = Compare(), - const Allocator& = Allocator()); + constexpr multimap(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); template<@\exposconcept{container-compatible-range}@ R> - multimap(from_range_t, R&& rg, - const Compare& comp = Compare(), const Allocator& = Allocator()); - multimap(const multimap& x); - multimap(multimap&& x); - explicit multimap(const Allocator&); - multimap(const multimap&, const type_identity_t&); - multimap(multimap&&, const type_identity_t&); - multimap(initializer_list, - const Compare& = Compare(), - const Allocator& = Allocator()); + constexpr multimap(from_range_t, R&& rg, + const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr multimap(const multimap& x); + constexpr multimap(multimap&& x); + constexpr explicit multimap(const Allocator&); + constexpr multimap(const multimap&, const type_identity_t&); + constexpr multimap(multimap&&, const type_identity_t&); + constexpr multimap(initializer_list, + const Compare& = Compare(), const Allocator& = Allocator()); template - multimap(InputIterator first, InputIterator last, const Allocator& a) + constexpr multimap(InputIterator first, InputIterator last, const Allocator& a) : multimap(first, last, Compare(), a) { } template<@\exposconcept{container-compatible-range}@ R> - multimap(from_range_t, R&& rg, const Allocator& a)) + constexpr multimap(from_range_t, R&& rg, const Allocator& a)) : multimap(from_range, std::forward(rg), Compare(), a) { } - multimap(initializer_list il, const Allocator& a) + constexpr multimap(initializer_list il, const Allocator& a) : multimap(il, Compare(), a) { } - ~multimap(); - multimap& operator=(const multimap& x); - multimap& operator=(multimap&& x) + constexpr ~multimap(); + constexpr multimap& operator=(const multimap& x); + constexpr multimap& operator=(multimap&& x) noexcept(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v); - multimap& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr multimap& operator=(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; + 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; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // \ref{multimap.modifiers}, modifiers - template iterator emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - iterator insert(const value_type& x); - iterator insert(value_type&& x); - template iterator insert(P&& x); - iterator insert(const_iterator position, const value_type& x); - iterator insert(const_iterator position, value_type&& x); - template iterator insert(const_iterator position, P&& x); + template constexpr iterator emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr iterator insert(const value_type& x); + constexpr iterator insert(value_type&& x); + template constexpr iterator insert(P&& x); + constexpr iterator insert(const_iterator position, const value_type& x); + constexpr iterator insert(const_iterator position, value_type&& x); + template constexpr iterator insert(const_iterator position, P&& x); template - void insert(InputIterator first, InputIterator last); + constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); - node_type extract(const_iterator position); - node_type extract(const key_type& x); + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); template node_type extract(K&& x); - iterator insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); - - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(multimap&) + constexpr iterator insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(multimap&) noexcept(allocator_traits::is_always_equal::value && is_nothrow_swappable_v); - void clear() noexcept; + constexpr void clear() noexcept; template - void merge(multimap& source); + constexpr void merge(multimap& source); template - void merge(multimap&& source); + constexpr void merge(multimap&& source); template - void merge(map& source); + constexpr void merge(map& source); template - void merge(map&& source); + constexpr void merge(map&& source); // observers - key_compare key_comp() const; - value_compare value_comp() const; + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; // map operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; - size_type count(const key_type& x) const; - template size_type count(const K& x) const; + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; - bool contains(const key_type& x) const; - template bool contains(const K& x) const; + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; template - pair equal_range(const K& x); + constexpr pair equal_range(const K& x); template - pair equal_range(const K& x) const; + constexpr pair equal_range(const K& x) const; }; template>, @@ -10597,7 +12472,7 @@ \indexlibraryctor{multimap}% \begin{itemdecl} -explicit multimap(const Compare& comp, const Allocator& = Allocator()); +constexpr explicit multimap(const Compare& comp, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -10615,9 +12490,8 @@ \indexlibraryctor{multimap}% \begin{itemdecl} template - multimap(InputIterator first, InputIterator last, - const Compare& comp = Compare(), - const Allocator& = Allocator()); + constexpr multimap(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -10642,7 +12516,8 @@ \indexlibraryctor{multimap}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - multimap(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr multimap(from_range_t, R&& rg, + const Compare& comp = Compare(), const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -10662,8 +12537,8 @@ \indexlibrarymember{insert}{multimap}% \begin{itemdecl} -template iterator insert(P&& x); -template iterator insert(const_iterator position, P&& x); +template constexpr iterator insert(P&& x); +template constexpr iterator insert(const_iterator position, P&& x); \end{itemdecl} \begin{itemdescr} @@ -10671,38 +12546,99 @@ \constraints \tcode{is_constructible_v} is \tcode{true}. -\pnum -\effects -The first form is equivalent to -\tcode{return emplace(std::forward

(x))}. The second form is -equivalent to \tcode{return emplace_hint(position, std::forward

(x))}. -\end{itemdescr} +\pnum +\effects +The first form is equivalent to +\tcode{return emplace(std::forward

(x))}. The second form is +equivalent to \tcode{return emplace_hint(position, std::forward

(x))}. +\end{itemdescr} + +\rSec3[multimap.erasure]{Erasure} + +\indexlibrarymember{erase_if}{multimap}% +\begin{itemdecl} +template + typename multimap::size_type + constexpr erase_if(multimap& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +\end{codeblock} +\end{itemdescr} + +\rSec2[associative.set.syn]{Header \tcode{} synopsis}% + +\indexheader{set}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{set}, class template \tcode{set} + template, class Allocator = allocator> + class set; + + template + constexpr bool operator==(const set& x, + const set& y); + template + constexpr @\placeholder{synth-three-way-result}@ operator<=>(const set& x, + @\itcorr@ const set& y); + + template + constexpr void swap(set& x, + set& y) + noexcept(noexcept(x.swap(y))); + + // \ref{set.erasure}, erasure for \tcode{set} + template + constexpr typename set::size_type + erase_if(set& c, Predicate pred); + + // \ref{multiset}, class template \tcode{multiset} + template, class Allocator = allocator> + class multiset; + + template + constexpr bool operator==(const multiset& x, + const multiset& y); + template + constexpr @\placeholder{synth-three-way-result}@ + operator<=>(const multiset& x, + const multiset& y); -\rSec3[multimap.erasure]{Erasure} + template + constexpr void swap(multiset& x, + multiset& y) + noexcept(noexcept(x.swap(y))); -\indexlibrarymember{erase_if}{multimap}% -\begin{itemdecl} -template - typename multimap::size_type - erase_if(multimap& c, Predicate pred); -\end{itemdecl} + // \ref{multiset.erasure}, erasure for \tcode{multiset} + template + constexpr typename multiset::size_type + erase_if(multiset& c, Predicate pred); -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -auto original_size = c.size(); -for (auto i = c.begin(), last = c.end(); i != last; ) { - if (pred(*i)) { - i = c.erase(i); - } else { - ++i; + namespace pmr { + template> + using set = std::set>; + + template> + using multiset = std::multiset>; } } -return original_size - c.size(); \end{codeblock} -\end{itemdescr} \rSec2[set]{Class template \tcode{set}} @@ -10722,7 +12658,7 @@ A \tcode{set} meets all of the requirements of a container\iref{container.reqmts}, of a reversible container\iref{container.rev.reqmts}, -of an allocator-aware container\iref{container.alloc.reqmts}. and +of an allocator-aware container\iref{container.alloc.reqmts}, and of an associative container\iref{associative.reqmts}. A \tcode{set} @@ -10749,6 +12685,10 @@ that are not described in one of these tables and 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, @@ -10775,130 +12715,132 @@ using insert_return_type = @\placeholdernc{insert-return-type}@; // \ref{set.cons}, construct/copy/destroy - set() : set(Compare()) { } - explicit set(const Compare& comp, const Allocator& = Allocator()); + constexpr set() : set(Compare()) { } + constexpr explicit set(const Compare& comp, const Allocator& = Allocator()); template - set(InputIterator first, InputIterator last, - const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr set(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); template<@\exposconcept{container-compatible-range}@ R> - set(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); - set(const set& x); - set(set&& x); - explicit set(const Allocator&); - set(const set&, const type_identity_t&); - set(set&&, const type_identity_t&); - set(initializer_list, const Compare& = Compare(), - const Allocator& = Allocator()); + constexpr set(from_range_t, R&& rg, + const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr set(const set& x); + constexpr set(set&& x); + constexpr explicit set(const Allocator&); + constexpr set(const set&, const type_identity_t&); + constexpr set(set&&, const type_identity_t&); + constexpr set(initializer_list, + const Compare& = Compare(), const Allocator& = Allocator()); template - set(InputIterator first, InputIterator last, const Allocator& a) + constexpr set(InputIterator first, InputIterator last, const Allocator& a) : set(first, last, Compare(), a) { } template<@\exposconcept{container-compatible-range}@ R> - set(from_range_t, R&& rg, const Allocator& a)) + constexpr set(from_range_t, R&& rg, const Allocator& a)) : set(from_range, std::forward(rg), Compare(), a) { } - set(initializer_list il, const Allocator& a) + constexpr set(initializer_list il, const Allocator& a) : set(il, Compare(), a) { } - ~set(); - set& operator=(const set& x); - set& operator=(set&& x) + constexpr ~set(); + constexpr set& operator=(const set& x); + constexpr set& operator=(set&& x) noexcept(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v); - set& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr set& operator=(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; + 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; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // \ref{set.modifiers}, modifiers - template pair emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - pair insert(const value_type& x); - pair insert(value_type&& x); - template pair insert(K&& x); - iterator insert(const_iterator position, const value_type& x); - iterator insert(const_iterator position, value_type&& x); - template iterator insert(const_iterator position, K&& x); + template constexpr pair emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr pair insert(const value_type& x); + constexpr pair insert(value_type&& x); + template constexpr pair insert(K&& x); + constexpr iterator insert(const_iterator position, const value_type& x); + constexpr iterator insert(const_iterator position, value_type&& x); + template constexpr iterator insert(const_iterator position, K&& x); template - void insert(InputIterator first, InputIterator last); + constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); - node_type extract(const_iterator position); - node_type extract(const key_type& x); - template node_type extract(K&& x); - insert_return_type insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); + template constexpr node_type extract(K&& x); + constexpr insert_return_type insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position) + constexpr iterator erase(iterator position) requires (!@\libconcept{same_as}@); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(set&) + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(set&) noexcept(allocator_traits::is_always_equal::value && is_nothrow_swappable_v); - void clear() noexcept; + constexpr void clear() noexcept; template - void merge(set& source); + constexpr void merge(set& source); template - void merge(set&& source); + constexpr void merge(set&& source); template - void merge(multiset& source); + constexpr void merge(multiset& source); template - void merge(multiset&& source); + constexpr void merge(multiset&& source); // observers - key_compare key_comp() const; - value_compare value_comp() const; + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; // set operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; - size_type count(const key_type& x) const; - template size_type count(const K& x) const; + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; - bool contains(const key_type& x) const; - template bool contains(const K& x) const; + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; template - pair equal_range(const K& x); + constexpr pair equal_range(const K& x); template - pair equal_range(const K& x) const; + constexpr pair equal_range(const K& x) const; }; template - set(InputIterator first, InputIterator last, - const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr set(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -10979,7 +12921,8 @@ \indexlibraryctor{set}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - set(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr set(from_range_t, R&& rg, const Compare& comp = Compare(), + const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -10999,7 +12942,7 @@ \indexlibrarymember{erase_if}{set}% \begin{itemdecl} template - typename set::size_type + constexpr typename set::size_type erase_if(set& c, Predicate pred); \end{itemdecl} @@ -11024,8 +12967,8 @@ \indexlibrarymember{insert}{set}% \begin{itemdecl} -template pair insert(K&& x); -template iterator insert(const_iterator hint, K&& x); +template constexpr pair insert(K&& x); +template constexpr iterator insert(const_iterator hint, K&& x); \end{itemdecl} \begin{itemdescr} @@ -11055,7 +12998,7 @@ \pnum \returns For the first overload, -the \tcode{bool} component of the returned pair is true +the \tcode{bool} component of the returned pair is \tcode{true} if and only if the insertion took place. The returned iterator points to the set element that is equivalent to \tcode{x}. @@ -11108,6 +13051,10 @@ that are not described in one of these tables and 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, @@ -11133,129 +13080,130 @@ using node_type = @\unspec@; // \ref{multiset.cons}, construct/copy/destroy - multiset() : multiset(Compare()) { } - explicit multiset(const Compare& comp, const Allocator& = Allocator()); + constexpr multiset() : multiset(Compare()) { } + constexpr explicit multiset(const Compare& comp, const Allocator& = Allocator()); template - multiset(InputIterator first, InputIterator last, - const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr multiset(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); template<@\exposconcept{container-compatible-range}@ R> - multiset(from_range_t, R&& rg, - const Compare& comp = Compare(), const Allocator& = Allocator()); - multiset(const multiset& x); - multiset(multiset&& x); - explicit multiset(const Allocator&); - multiset(const multiset&, const type_identity_t&); - multiset(multiset&&, const type_identity_t&); - multiset(initializer_list, const Compare& = Compare(), - const Allocator& = Allocator()); + constexpr multiset(from_range_t, R&& rg, + const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr multiset(const multiset& x); + constexpr multiset(multiset&& x); + constexpr explicit multiset(const Allocator&); + constexpr multiset(const multiset&, const type_identity_t&); + constexpr multiset(multiset&&, const type_identity_t&); + constexpr multiset(initializer_list, const Compare& = Compare(), + const Allocator& = Allocator()); template - multiset(InputIterator first, InputIterator last, const Allocator& a) + constexpr multiset(InputIterator first, InputIterator last, const Allocator& a) : multiset(first, last, Compare(), a) { } template<@\exposconcept{container-compatible-range}@ R> - multiset(from_range_t, R&& rg, const Allocator& a)) + constexpr multiset(from_range_t, R&& rg, const Allocator& a)) : multiset(from_range, std::forward(rg), Compare(), a) { } - multiset(initializer_list il, const Allocator& a) + constexpr multiset(initializer_list il, const Allocator& a) : multiset(il, Compare(), a) { } - ~multiset(); - multiset& operator=(const multiset& x); - multiset& operator=(multiset&& x) + constexpr ~multiset(); + constexpr multiset& operator=(const multiset& x); + constexpr multiset& operator=(multiset&& x) noexcept(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v); - multiset& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr multiset& operator=(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; + 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; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // modifiers - template iterator emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - iterator insert(const value_type& x); - iterator insert(value_type&& x); - iterator insert(const_iterator position, const value_type& x); - iterator insert(const_iterator position, value_type&& x); + template constexpr iterator emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr iterator insert(const value_type& x); + constexpr iterator insert(value_type&& x); + constexpr iterator insert(const_iterator position, const value_type& x); + constexpr iterator insert(const_iterator position, value_type&& x); template - void insert(InputIterator first, InputIterator last); + constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); - node_type extract(const_iterator position); - node_type extract(const key_type& x); - template node_type extract(K&& x); - iterator insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); + template constexpr node_type extract(K&& x); + constexpr iterator insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position) + constexpr iterator erase(iterator position) requires (!@\libconcept{same_as}@); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(multiset&) + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(multiset&) noexcept(allocator_traits::is_always_equal::value && is_nothrow_swappable_v); - void clear() noexcept; + constexpr void clear() noexcept; template - void merge(multiset& source); + constexpr void merge(multiset& source); template - void merge(multiset&& source); + constexpr void merge(multiset&& source); template - void merge(set& source); + constexpr void merge(set& source); template - void merge(set&& source); + constexpr void merge(set&& source); // observers - key_compare key_comp() const; - value_compare value_comp() const; + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; // set operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; - size_type count(const key_type& x) const; - template size_type count(const K& x) const; + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; - bool contains(const key_type& x) const; - template bool contains(const K& x) const; + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; template - pair equal_range(const K& x); + constexpr pair equal_range(const K& x); template - pair equal_range(const K& x) const; + constexpr pair equal_range(const K& x) const; }; template - multiset(InputIterator first, InputIterator last, - const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr multiset(InputIterator first, InputIterator last, + const Compare& comp = Compare(), const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -11336,7 +13284,8 @@ \indexlibraryctor{multiset}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - multiset(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); + constexpr multiset(from_range_t, R&& rg, const Compare& comp = Compare(), + const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -11357,7 +13306,7 @@ \indexlibrarymember{erase_if}{multiset}% \begin{itemdecl} template - typename multiset::size_type + constexpr typename multiset::size_type erase_if(multiset& c, Predicate pred); \end{itemdecl} @@ -11380,13 +13329,13 @@ \rSec1[unord]{Unordered associative containers} -\rSec2[unord.general]{In general} +\rSec2[unord.general]{General} \pnum -The header \libheader{unordered_map} defines the class templates -\tcode{unordered_map} and -\tcode{unordered_multimap}; the header \libheader{unordered_set} defines the class templates -\tcode{unordered_set} and \tcode{unordered_multiset}. +The header \libheaderrefx{unordered_map}{unord.map.syn} defines the class +templates \tcode{unordered_map} and \tcode{unordered_multimap}; +the header \libheaderrefx{unordered_set}{unord.set.syn} defines the class +templates \tcode{unordered_set} and \tcode{unordered_multiset}. \pnum The exposition-only alias templates @@ -11423,31 +13372,31 @@ class unordered_multimap; template - bool operator==(const unordered_map& a, - const unordered_map& b); + constexpr bool operator==(const unordered_map& a, + const unordered_map& b); template - bool operator==(const unordered_multimap& a, - const unordered_multimap& b); + constexpr bool operator==(const unordered_multimap& a, + const unordered_multimap& b); template - void swap(unordered_map& x, - unordered_map& y) + constexpr void swap(unordered_map& x, + unordered_map& y) noexcept(noexcept(x.swap(y))); template - void swap(unordered_multimap& x, - unordered_multimap& y) + constexpr void swap(unordered_multimap& x, + unordered_multimap& y) noexcept(noexcept(x.swap(y))); // \ref{unord.map.erasure}, erasure for \tcode{unordered_map} template - typename unordered_map::size_type + constexpr typename unordered_map::size_type erase_if(unordered_map& c, Predicate pred); // \ref{unord.multimap.erasure}, erasure for \tcode{unordered_multimap} template - typename unordered_multimap::size_type + constexpr typename unordered_multimap::size_type erase_if(unordered_multimap& c, Predicate pred); namespace pmr { @@ -11470,74 +13419,6 @@ } \end{codeblock} -\rSec2[unord.set.syn]{Header \tcode{} synopsis} - -\indexheader{unordered_set}% -\indexlibraryglobal{unordered_set}% -\indexlibraryglobal{unordered_multiset}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} - -namespace std { - // \ref{unord.set}, class template \tcode{unordered_set} - template, - class Pred = equal_to, - class Alloc = allocator> - class unordered_set; - - // \ref{unord.multiset}, class template \tcode{unordered_multiset} - template, - class Pred = equal_to, - class Alloc = allocator> - class unordered_multiset; - - template - bool operator==(const unordered_set& a, - const unordered_set& b); - - template - bool operator==(const unordered_multiset& a, - const unordered_multiset& b); - - template - void swap(unordered_set& x, - unordered_set& y) - noexcept(noexcept(x.swap(y))); - - template - void swap(unordered_multiset& x, - unordered_multiset& y) - noexcept(noexcept(x.swap(y))); - - // \ref{unord.set.erasure}, erasure for \tcode{unordered_set} - template - typename unordered_set::size_type - erase_if(unordered_set& c, Predicate pred); - - // \ref{unord.multiset.erasure}, erasure for \tcode{unordered_multiset} - template - typename unordered_multiset::size_type - erase_if(unordered_multiset& c, Predicate pred); - - namespace pmr { - template, - class Pred = equal_to> - using unordered_set = std::unordered_set>; - - template, - class Pred = equal_to> - using unordered_multiset = std::unordered_multiset>; - } -} -\end{codeblock} - \rSec2[unord.map]{Class template \tcode{unordered_map}}% \indexlibraryglobal{unordered_map} @@ -11570,6 +13451,10 @@ are not described in one of the requirement tables, or for which there is additional semantic information. +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. + \indexlibraryglobal{unordered_map}% \begin{codeblock} namespace std { @@ -11602,193 +13487,193 @@ using insert_return_type = @\placeholdernc{insert-return-type}@; // \ref{unord.map.cnstr}, construct/copy/destroy - unordered_map(); - explicit unordered_map(size_type n, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_map(); + constexpr explicit unordered_map(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template - unordered_map(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_map(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_map(from_range_t, R&& rg, size_type n = @\seebelow@, + constexpr unordered_map(from_range_t, R&& rg, size_type n = @\seebelow@, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); - unordered_map(const unordered_map&); - unordered_map(unordered_map&&); - explicit unordered_map(const Allocator&); - unordered_map(const unordered_map&, const type_identity_t&); - unordered_map(unordered_map&&, const type_identity_t&); - unordered_map(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); - unordered_map(size_type n, const allocator_type& a) + constexpr unordered_map(const unordered_map&); + constexpr unordered_map(unordered_map&&); + constexpr explicit unordered_map(const Allocator&); + constexpr unordered_map(const unordered_map&, const type_identity_t&); + constexpr unordered_map(unordered_map&&, const type_identity_t&); + constexpr unordered_map(initializer_list il, size_type n = @\seebelow@, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + constexpr unordered_map(size_type n, const allocator_type& a) : unordered_map(n, hasher(), key_equal(), a) { } - unordered_map(size_type n, const hasher& hf, const allocator_type& a) + constexpr unordered_map(size_type n, const hasher& hf, const allocator_type& a) : unordered_map(n, hf, key_equal(), a) { } template - unordered_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a) + constexpr unordered_map(InputIterator f, InputIterator l, size_type n, + const allocator_type& a) : unordered_map(f, l, n, hasher(), key_equal(), a) { } template - unordered_map(InputIterator f, InputIterator l, size_type n, const hasher& hf, + constexpr unordered_map(InputIterator f, InputIterator l, size_type n, const hasher& hf, const allocator_type& a) : unordered_map(f, l, n, hf, key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_map(from_range_t, R&& rg, size_type n, const allocator_type& a) + constexpr unordered_map(from_range_t, R&& rg, size_type n, const allocator_type& a) : unordered_map(from_range, std::forward(rg), n, hasher(), key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_map(from_range_t, R&& rg, size_type n, const hasher& hf, const allocator_type& a) + constexpr unordered_map(from_range_t, R&& rg, size_type n, const hasher& hf, + const allocator_type& a) : unordered_map(from_range, std::forward(rg), n, hf, key_equal(), a) { } - unordered_map(initializer_list il, size_type n, const allocator_type& a) + constexpr unordered_map(initializer_list il, size_type n, + const allocator_type& a) : unordered_map(il, n, hasher(), key_equal(), a) { } - unordered_map(initializer_list il, size_type n, const hasher& hf, + constexpr unordered_map(initializer_list il, size_type n, const hasher& hf, const allocator_type& a) : unordered_map(il, n, hf, key_equal(), a) { } - ~unordered_map(); - unordered_map& operator=(const unordered_map&); - unordered_map& operator=(unordered_map&&) + constexpr ~unordered_map(); + constexpr unordered_map& operator=(const unordered_map&); + constexpr unordered_map& operator=(unordered_map&&) noexcept(allocator_traits::is_always_equal::value && is_nothrow_move_assignable_v && is_nothrow_move_assignable_v); - unordered_map& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr unordered_map& operator=(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; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // \ref{unord.map.modifiers}, modifiers - template pair emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - pair insert(const value_type& obj); - pair insert(value_type&& obj); - template pair insert(P&& obj); - iterator insert(const_iterator hint, const value_type& obj); - iterator insert(const_iterator hint, value_type&& obj); - template iterator insert(const_iterator hint, P&& obj); - template void insert(InputIterator first, InputIterator last); + template constexpr pair emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr pair insert(const value_type& obj); + constexpr pair insert(value_type&& obj); + template constexpr pair insert(P&& obj); + constexpr iterator insert(const_iterator hint, const value_type& obj); + constexpr iterator insert(const_iterator hint, value_type&& obj); + template constexpr iterator insert(const_iterator hint, P&& obj); + template constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); - node_type extract(const_iterator position); - node_type extract(const key_type& x); - template node_type extract(K&& x); - insert_return_type insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); + template constexpr node_type extract(K&& x); + constexpr insert_return_type insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); template - pair try_emplace(const key_type& k, Args&&... args); + constexpr pair try_emplace(const key_type& k, Args&&... args); template - pair try_emplace(key_type&& k, Args&&... args); + constexpr pair try_emplace(key_type&& k, Args&&... args); template - pair try_emplace(K&& k, Args&&... args); + constexpr pair try_emplace(K&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template - iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); template - pair insert_or_assign(const key_type& k, M&& obj); + constexpr pair insert_or_assign(const key_type& k, M&& obj); template - pair insert_or_assign(key_type&& k, M&& obj); + constexpr pair insert_or_assign(key_type&& k, M&& obj); template - pair insert_or_assign(K&& k, M&& obj); + constexpr pair insert_or_assign(K&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); - - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& k); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(unordered_map&) + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& k); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(unordered_map&) noexcept(allocator_traits::is_always_equal::value && - is_nothrow_swappable_v && - is_nothrow_swappable_v); - void clear() noexcept; + is_nothrow_swappable_v && is_nothrow_swappable_v); + constexpr void clear() noexcept; template - void merge(unordered_map& source); + constexpr void merge(unordered_map& source); template - void merge(unordered_map&& source); + constexpr void merge(unordered_map&& source); template - void merge(unordered_multimap& source); + constexpr void merge(unordered_multimap& source); template - void merge(unordered_multimap&& source); + constexpr void merge(unordered_multimap&& source); // observers - hasher hash_function() const; - key_equal key_eq() const; + constexpr hasher hash_function() const; + constexpr key_equal key_eq() const; // map operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; + constexpr iterator find(const key_type& k); + constexpr const_iterator find(const key_type& k) const; template - iterator find(const K& k); + constexpr iterator find(const K& k); template - const_iterator find(const K& k) const; - size_type count(const key_type& k) const; + constexpr const_iterator find(const K& k) const; + constexpr size_type count(const key_type& k) const; template - size_type count(const K& k) const; - bool contains(const key_type& k) const; + constexpr size_type count(const K& k) const; + constexpr bool contains(const key_type& k) const; template - bool contains(const K& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + constexpr bool contains(const K& k) const; + constexpr pair equal_range(const key_type& k); + constexpr pair equal_range(const key_type& k) const; template - pair equal_range(const K& k); + constexpr pair equal_range(const K& k); template - pair equal_range(const K& k) const; + constexpr pair equal_range(const K& k) const; // \ref{unord.map.elem}, element access - mapped_type& operator[](const key_type& k); - mapped_type& operator[](key_type&& k); - template mapped_type& operator[](K&& k); - mapped_type& at(const key_type& k); - const mapped_type& at(const key_type& k) const; - template mapped_type& at(const K& k); - template const mapped_type& at(const K& k) const; + constexpr mapped_type& operator[](const key_type& k); + constexpr mapped_type& operator[](key_type&& k); + template constexpr mapped_type& operator[](K&& k); + constexpr mapped_type& at(const key_type& k); + constexpr const mapped_type& at(const key_type& k) const; + template constexpr mapped_type& at(const K& k); + template constexpr const mapped_type& at(const K& k) const; // bucket interface - size_type bucket_count() const noexcept; - size_type max_bucket_count() const noexcept; - size_type bucket_size(size_type n) const; - size_type bucket(const key_type& k) const; - template size_type bucket(const K& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - const_local_iterator cbegin(size_type n) const; - const_local_iterator cend(size_type n) const; + constexpr size_type bucket_count() const noexcept; + constexpr size_type max_bucket_count() const noexcept; + constexpr size_type bucket_size(size_type n) const; + constexpr size_type bucket(const key_type& k) const; + template constexpr size_type bucket(const K& k) const; + constexpr local_iterator begin(size_type n); + constexpr const_local_iterator begin(size_type n) const; + constexpr local_iterator end(size_type n); + constexpr const_local_iterator end(size_type n) const; + constexpr const_local_iterator cbegin(size_type n) const; + constexpr const_local_iterator cend(size_type n) const; // hash policy - float load_factor() const noexcept; - float max_load_factor() const noexcept; - void max_load_factor(float z); - void rehash(size_type n); - void reserve(size_type n); + constexpr float load_factor() const noexcept; + constexpr float max_load_factor() const noexcept; + constexpr void max_load_factor(float z); + constexpr void rehash(size_type n); + constexpr void reserve(size_type n); }; template - unordered_map(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_map(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_map(from_range_t, R&& rg, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); -unordered_map(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_map(from_range_t, R&& rg, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +constexpr unordered_map(initializer_list il, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); \end{itemdecl} \begin{itemdescr} @@ -11935,7 +13816,7 @@ \indexlibrarymember{unordered_map}{operator[]}% \indextext{\idxcode{unordered_map}!element access}% \begin{itemdecl} -mapped_type& operator[](const key_type& k); +constexpr mapped_type& operator[](const key_type& k); \end{itemdecl} \begin{itemdescr} @@ -11947,7 +13828,7 @@ \indexlibrarymember{unordered_map}{operator[]}% \indextext{\idxcode{unordered_map}!element access}% \begin{itemdecl} -mapped_type& operator[](key_type&& k); +constexpr mapped_type& operator[](key_type&& k); \end{itemdecl} \begin{itemdescr} @@ -11959,7 +13840,7 @@ \indexlibrarymember{unordered_map}{operator[]}% \indextext{\idxcode{unordered_map}!element access}% \begin{itemdecl} -template mapped_type& operator[](K&& k); +template constexpr mapped_type& operator[](K&& k); \end{itemdecl} \begin{itemdescr} @@ -11976,8 +13857,8 @@ \indexlibrarymember{unordered_map}{at}% \indextext{\idxcode{unordered_map}!element access}% \begin{itemdecl} -mapped_type& at(const key_type& k); -const mapped_type& at(const key_type& k) const; +constexpr mapped_type& at(const key_type& k); +constexpr const mapped_type& at(const key_type& k) const; \end{itemdecl} \begin{itemdescr} @@ -11993,8 +13874,8 @@ \indexlibrarymember{unordered_map}{at}% \indextext{\idxcode{unordered_map}!element access}% \begin{itemdecl} -template mapped_type& at(const K& k); -template const mapped_type& at(const K& k) const; +template constexpr mapped_type& at(const K& k); +template constexpr const mapped_type& at(const K& k) const; \end{itemdecl} \begin{itemdescr} @@ -12022,7 +13903,7 @@ \indexlibrarymember{unordered_map}{insert}% \begin{itemdecl} template - pair insert(P&& obj); + constexpr pair insert(P&& obj); \end{itemdecl} \begin{itemdescr} @@ -12039,7 +13920,7 @@ \indexlibrarymember{unordered_map}{insert}% \begin{itemdecl} template - iterator insert(const_iterator hint, P&& obj); + constexpr iterator insert(const_iterator hint, P&& obj); \end{itemdecl} \begin{itemdescr} @@ -12056,9 +13937,9 @@ \indexlibrarymember{try_emplace}{unordered_map}% \begin{itemdecl} template - pair try_emplace(const key_type& k, Args&&... args); + constexpr pair try_emplace(const key_type& k, Args&&... args); template - iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -12094,9 +13975,9 @@ \indexlibrarymember{try_emplace}{unordered_map}% \begin{itemdecl} template - pair try_emplace(key_type&& k, Args&&... args); + constexpr pair try_emplace(key_type&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -12132,9 +14013,9 @@ \indexlibrarymember{try_emplace}{unordered_map}% \begin{itemdecl} template - pair try_emplace(K&& k, Args&&... args); + constexpr pair try_emplace(K&& k, Args&&... args); template - iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -12181,9 +14062,9 @@ \indexlibrarymember{insert_or_assign}{unordered_map}% \begin{itemdecl} template - pair insert_or_assign(const key_type& k, M&& obj); + constexpr pair insert_or_assign(const key_type& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); \end{itemdecl} \begin{itemdescr} @@ -12221,9 +14102,9 @@ \indexlibrarymember{insert_or_assign}{unordered_map}% \begin{itemdecl} template - pair insert_or_assign(key_type&& k, M&& obj); + constexpr pair insert_or_assign(key_type&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); \end{itemdecl} \begin{itemdescr} @@ -12261,9 +14142,9 @@ \indexlibrarymember{insert_or_assign}{unordered_map}% \begin{itemdecl} template - pair insert_or_assign(K&& k, M&& obj); + constexpr pair insert_or_assign(K&& k, M&& obj); template - iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); \end{itemdecl} \begin{itemdescr} @@ -12312,7 +14193,7 @@ \indexlibrarymember{erase_if}{unordered_map}% \begin{itemdecl} template - typename unordered_map::size_type + constexpr typename unordered_map::size_type erase_if(unordered_map& c, Predicate pred); \end{itemdecl} @@ -12365,6 +14246,10 @@ that are not described in one of the requirement tables, or for which there is additional semantic information. +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. + \indexlibraryglobal{unordered_multimap}% \begin{codeblock} namespace std { @@ -12396,162 +14281,159 @@ using node_type = @\unspec@; // \ref{unord.multimap.cnstr}, construct/copy/destroy - unordered_multimap(); - explicit unordered_multimap(size_type n, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multimap(); + constexpr explicit unordered_multimap(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template - unordered_multimap(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multimap(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_multimap(from_range_t, R&& rg, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); - unordered_multimap(const unordered_multimap&); - unordered_multimap(unordered_multimap&&); - explicit unordered_multimap(const Allocator&); - unordered_multimap(const unordered_multimap&, const type_identity_t&); - unordered_multimap(unordered_multimap&&, const type_identity_t&); - unordered_multimap(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); - unordered_multimap(size_type n, const allocator_type& a) + constexpr unordered_multimap(from_range_t, R&& rg, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + constexpr unordered_multimap(const unordered_multimap&); + constexpr unordered_multimap(unordered_multimap&&); + constexpr explicit unordered_multimap(const Allocator&); + constexpr unordered_multimap(const unordered_multimap&, const type_identity_t&); + constexpr unordered_multimap(unordered_multimap&&, const type_identity_t&); + constexpr unordered_multimap(initializer_list il, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + constexpr unordered_multimap(size_type n, const allocator_type& a) : unordered_multimap(n, hasher(), key_equal(), a) { } - unordered_multimap(size_type n, const hasher& hf, const allocator_type& a) + constexpr unordered_multimap(size_type n, const hasher& hf, const allocator_type& a) : unordered_multimap(n, hf, key_equal(), a) { } template - unordered_multimap(InputIterator f, InputIterator l, size_type n, const allocator_type& a) + constexpr unordered_multimap(InputIterator f, InputIterator l, size_type n, + const allocator_type& a) : unordered_multimap(f, l, n, hasher(), key_equal(), a) { } template - unordered_multimap(InputIterator f, InputIterator l, size_type n, const hasher& hf, - const allocator_type& a) + constexpr unordered_multimap(InputIterator f, InputIterator l, size_type n, + const hasher& hf, const allocator_type& a) : unordered_multimap(f, l, n, hf, key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_multimap(from_range_t, R&& rg, size_type n, const allocator_type& a) + constexpr unordered_multimap(from_range_t, R&& rg, size_type n, const allocator_type& a) : unordered_multimap(from_range, std::forward(rg), n, hasher(), key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_multimap(from_range_t, R&& rg, size_type n, const hasher& hf, + constexpr unordered_multimap(from_range_t, R&& rg, size_type n, const hasher& hf, const allocator_type& a) : unordered_multimap(from_range, std::forward(rg), n, hf, key_equal(), a) { } - unordered_multimap(initializer_list il, size_type n, const allocator_type& a) + constexpr unordered_multimap(initializer_list il, size_type n, + const allocator_type& a) : unordered_multimap(il, n, hasher(), key_equal(), a) { } - unordered_multimap(initializer_list il, size_type n, const hasher& hf, + constexpr unordered_multimap(initializer_list il, size_type n, const hasher& hf, const allocator_type& a) : unordered_multimap(il, n, hf, key_equal(), a) { } - ~unordered_multimap(); - unordered_multimap& operator=(const unordered_multimap&); - unordered_multimap& operator=(unordered_multimap&&) + constexpr ~unordered_multimap(); + constexpr unordered_multimap& operator=(const unordered_multimap&); + constexpr unordered_multimap& operator=(unordered_multimap&&) noexcept(allocator_traits::is_always_equal::value && - is_nothrow_move_assignable_v && - is_nothrow_move_assignable_v); - unordered_multimap& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + is_nothrow_move_assignable_v && is_nothrow_move_assignable_v); + constexpr unordered_multimap& operator=(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; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // \ref{unord.multimap.modifiers}, modifiers - template iterator emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - iterator insert(const value_type& obj); - iterator insert(value_type&& obj); - template iterator insert(P&& obj); - iterator insert(const_iterator hint, const value_type& obj); - iterator insert(const_iterator hint, value_type&& obj); - template iterator insert(const_iterator hint, P&& obj); - template void insert(InputIterator first, InputIterator last); + template constexpr iterator emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr iterator insert(const value_type& obj); + constexpr iterator insert(value_type&& obj); + template constexpr iterator insert(P&& obj); + constexpr iterator insert(const_iterator hint, const value_type& obj); + constexpr iterator insert(const_iterator hint, value_type&& obj); + template constexpr iterator insert(const_iterator hint, P&& obj); + template constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); - - node_type extract(const_iterator position); - node_type extract(const key_type& x); - template node_type extract(K&& x); - iterator insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); - - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& k); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(unordered_multimap&) + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); + + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); + template constexpr node_type extract(K&& x); + constexpr iterator insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& k); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(unordered_multimap&) noexcept(allocator_traits::is_always_equal::value && - is_nothrow_swappable_v && - is_nothrow_swappable_v); - void clear() noexcept; + is_nothrow_swappable_v && is_nothrow_swappable_v); + constexpr void clear() noexcept; template - void merge(unordered_multimap& source); + constexpr void merge(unordered_multimap& source); template - void merge(unordered_multimap&& source); + constexpr void merge(unordered_multimap&& source); template - void merge(unordered_map& source); + constexpr void merge(unordered_map& source); template - void merge(unordered_map&& source); + constexpr void merge(unordered_map&& source); // observers - hasher hash_function() const; - key_equal key_eq() const; + constexpr hasher hash_function() const; + constexpr key_equal key_eq() const; // map operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; + constexpr iterator find(const key_type& k); + constexpr const_iterator find(const key_type& k) const; template - iterator find(const K& k); + constexpr iterator find(const K& k); template - const_iterator find(const K& k) const; - size_type count(const key_type& k) const; + constexpr const_iterator find(const K& k) const; + constexpr size_type count(const key_type& k) const; template - size_type count(const K& k) const; - bool contains(const key_type& k) const; + constexpr size_type count(const K& k) const; + constexpr bool contains(const key_type& k) const; template - bool contains(const K& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + constexpr bool contains(const K& k) const; + constexpr pair equal_range(const key_type& k); + constexpr pair equal_range(const key_type& k) const; template - pair equal_range(const K& k); + constexpr pair equal_range(const K& k); template - pair equal_range(const K& k) const; + constexpr pair equal_range(const K& k) const; // bucket interface - size_type bucket_count() const noexcept; - size_type max_bucket_count() const noexcept; - size_type bucket_size(size_type n) const; - size_type bucket(const key_type& k) const; - template size_type bucket(const K& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - const_local_iterator cbegin(size_type n) const; - const_local_iterator cend(size_type n) const; + constexpr size_type bucket_count() const noexcept; + constexpr size_type max_bucket_count() const noexcept; + constexpr size_type bucket_size(size_type n) const; + constexpr size_type bucket(const key_type& k) const; + template constexpr size_type bucket(const K& k) const; + constexpr local_iterator begin(size_type n); + constexpr const_local_iterator begin(size_type n) const; + constexpr local_iterator end(size_type n); + constexpr const_local_iterator end(size_type n) const; + constexpr const_local_iterator cbegin(size_type n) const; + constexpr const_local_iterator cend(size_type n) const; // hash policy - float load_factor() const noexcept; - float max_load_factor() const noexcept; - void max_load_factor(float z); - void rehash(size_type n); - void reserve(size_type n); + constexpr float load_factor() const noexcept; + constexpr float max_load_factor() const noexcept; + constexpr void max_load_factor(float z); + constexpr void rehash(size_type n); + constexpr void reserve(size_type n); }; template - unordered_multimap(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multimap(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_multimap(from_range_t, R&& rg, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); -unordered_multimap(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multimap(from_range_t, R&& rg, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +constexpr unordered_multimap(initializer_list il, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); \end{itemdecl} \begin{itemdescr} @@ -12701,7 +14579,7 @@ \indexlibrarymember{unordered_multimap}{insert}% \begin{itemdecl} template - iterator insert(P&& obj); + constexpr iterator insert(P&& obj); \end{itemdecl} \begin{itemdescr} @@ -12717,45 +14595,113 @@ \indexlibrarymember{unordered_multimap}{insert}% \begin{itemdecl} template - iterator insert(const_iterator hint, P&& obj); + constexpr iterator insert(const_iterator hint, P&& obj); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Equivalent to: +\tcode{return emplace_hint(hint, std::forward

(obj));} +\end{itemdescr} + +\rSec3[unord.multimap.erasure]{Erasure} + +\indexlibrarymember{erase_if}{unordered_multimap}% +\begin{itemdecl} +template + constexpr typename unordered_multimap::size_type + erase_if(unordered_multimap& c, Predicate pred); \end{itemdecl} -\begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v} is \tcode{true}. +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +\end{codeblock} +\end{itemdescr} + +\rSec2[unord.set.syn]{Header \tcode{} synopsis} + +\indexheader{unordered_set}% +\indexlibraryglobal{unordered_set}% +\indexlibraryglobal{unordered_multiset}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{unord.set}, class template \tcode{unordered_set} + template, + class Pred = equal_to, + class Alloc = allocator> + class unordered_set; + + // \ref{unord.multiset}, class template \tcode{unordered_multiset} + template, + class Pred = equal_to, + class Alloc = allocator> + class unordered_multiset; + + template + constexpr bool operator==(const unordered_set& a, + const unordered_set& b); + + template + constexpr bool operator==(const unordered_multiset& a, + const unordered_multiset& b); + + template + constexpr void swap(unordered_set& x, + unordered_set& y) + noexcept(noexcept(x.swap(y))); + + template + constexpr void swap(unordered_multiset& x, + unordered_multiset& y) + noexcept(noexcept(x.swap(y))); -\pnum -\effects -Equivalent to: -\tcode{return emplace_hint(hint, std::forward

(obj));} -\end{itemdescr} + // \ref{unord.set.erasure}, erasure for \tcode{unordered_set} + template + constexpr typename unordered_set::size_type + erase_if(unordered_set& c, Predicate pred); -\rSec3[unord.multimap.erasure]{Erasure} + // \ref{unord.multiset.erasure}, erasure for \tcode{unordered_multiset} + template + constexpr typename unordered_multiset::size_type + erase_if(unordered_multiset& c, Predicate pred); -\indexlibrarymember{erase_if}{unordered_multimap}% -\begin{itemdecl} -template - typename unordered_multimap::size_type - erase_if(unordered_multimap& c, Predicate pred); -\end{itemdecl} + namespace pmr { + template, + class Pred = equal_to> + using unordered_set = std::unordered_set>; -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -auto original_size = c.size(); -for (auto i = c.begin(), last = c.end(); i != last; ) { - if (pred(*i)) { - i = c.erase(i); - } else { - ++i; + template, + class Pred = equal_to> + using unordered_multiset = std::unordered_multiset>; } } -return original_size - c.size(); \end{codeblock} -\end{itemdescr} \rSec2[unord.set]{Class template \tcode{unordered_set}}% \indexlibraryglobal{unordered_set} @@ -12790,6 +14736,10 @@ are not described in one of the requirement tables, or for which there is additional semantic information. +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. + \indexlibraryglobal{unordered_set}% \begin{codeblock} namespace std { @@ -12820,161 +14770,159 @@ using insert_return_type = @\placeholdernc{insert-return-type}@; // \ref{unord.set.cnstr}, construct/copy/destroy - unordered_set(); - explicit unordered_set(size_type n, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_set(); + constexpr explicit unordered_set(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template - unordered_set(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_set(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_set(from_range_t, R&& rg, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); - unordered_set(const unordered_set&); - unordered_set(unordered_set&&); - explicit unordered_set(const Allocator&); - unordered_set(const unordered_set&, const type_identity_t&); - unordered_set(unordered_set&&, const type_identity_t&); - unordered_set(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); - unordered_set(size_type n, const allocator_type& a) + constexpr unordered_set(from_range_t, R&& rg, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + constexpr unordered_set(const unordered_set&); + constexpr unordered_set(unordered_set&&); + constexpr explicit unordered_set(const Allocator&); + constexpr unordered_set(const unordered_set&, const type_identity_t&); + constexpr unordered_set(unordered_set&&, const type_identity_t&); + constexpr unordered_set(initializer_list il, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + constexpr unordered_set(size_type n, const allocator_type& a) : unordered_set(n, hasher(), key_equal(), a) { } - unordered_set(size_type n, const hasher& hf, const allocator_type& a) + constexpr unordered_set(size_type n, const hasher& hf, const allocator_type& a) : unordered_set(n, hf, key_equal(), a) { } template - unordered_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a) + constexpr unordered_set(InputIterator f, InputIterator l, size_type n, + const allocator_type& a) : unordered_set(f, l, n, hasher(), key_equal(), a) { } template - unordered_set(InputIterator f, InputIterator l, size_type n, const hasher& hf, - const allocator_type& a) + constexpr unordered_set(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a) : unordered_set(f, l, n, hf, key_equal(), a) { } - unordered_set(initializer_list il, size_type n, const allocator_type& a) + constexpr unordered_set(initializer_list il, size_type n, + const allocator_type& a) : unordered_set(il, n, hasher(), key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_set(from_range_t, R&& rg, size_type n, const allocator_type& a) + constexpr unordered_set(from_range_t, R&& rg, size_type n, const allocator_type& a) : unordered_set(from_range, std::forward(rg), n, hasher(), key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_set(from_range_t, R&& rg, size_type n, const hasher& hf, const allocator_type& a) + constexpr unordered_set(from_range_t, R&& rg, size_type n, const hasher& hf, + const allocator_type& a) : unordered_set(from_range, std::forward(rg), n, hf, key_equal(), a) { } - unordered_set(initializer_list il, size_type n, const hasher& hf, - const allocator_type& a) + constexpr unordered_set(initializer_list il, size_type n, const hasher& hf, + const allocator_type& a) : unordered_set(il, n, hf, key_equal(), a) { } - ~unordered_set(); - unordered_set& operator=(const unordered_set&); - unordered_set& operator=(unordered_set&&) + constexpr ~unordered_set(); + constexpr unordered_set& operator=(const unordered_set&); + constexpr unordered_set& operator=(unordered_set&&) noexcept(allocator_traits::is_always_equal::value && - is_nothrow_move_assignable_v && - is_nothrow_move_assignable_v); - unordered_set& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + is_nothrow_move_assignable_v && is_nothrow_move_assignable_v); + constexpr unordered_set& operator=(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; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // \ref{unord.set.modifiers}, modifiers - template pair emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - pair insert(const value_type& obj); - pair insert(value_type&& obj); - template pair insert(K&& obj); - iterator insert(const_iterator hint, const value_type& obj); - iterator insert(const_iterator hint, value_type&& obj); - template iterator insert(const_iterator hint, K&& obj); - template void insert(InputIterator first, InputIterator last); + template constexpr pair emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr pair insert(const value_type& obj); + constexpr pair insert(value_type&& obj); + template constexpr pair insert(K&& obj); + constexpr iterator insert(const_iterator hint, const value_type& obj); + constexpr iterator insert(const_iterator hint, value_type&& obj); + template constexpr iterator insert(const_iterator hint, K&& obj); + template constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); - node_type extract(const_iterator position); - node_type extract(const key_type& x); - template node_type extract(K&& x); - insert_return_type insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); + template constexpr node_type extract(K&& x); + constexpr insert_return_type insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position) + constexpr iterator erase(iterator position) requires (!@\libconcept{same_as}@); - iterator erase(const_iterator position); - size_type erase(const key_type& k); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(unordered_set&) + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& k); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(unordered_set&) noexcept(allocator_traits::is_always_equal::value && - is_nothrow_swappable_v && - is_nothrow_swappable_v); - void clear() noexcept; + is_nothrow_swappable_v && is_nothrow_swappable_v); + constexpr void clear() noexcept; template - void merge(unordered_set& source); + constexpr void merge(unordered_set& source); template - void merge(unordered_set&& source); + constexpr void merge(unordered_set&& source); template - void merge(unordered_multiset& source); + constexpr void merge(unordered_multiset& source); template - void merge(unordered_multiset&& source); + constexpr void merge(unordered_multiset&& source); // observers - hasher hash_function() const; - key_equal key_eq() const; + constexpr hasher hash_function() const; + constexpr key_equal key_eq() const; // set operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; + constexpr iterator find(const key_type& k); + constexpr const_iterator find(const key_type& k) const; template - iterator find(const K& k); + constexpr iterator find(const K& k); template - const_iterator find(const K& k) const; - size_type count(const key_type& k) const; + constexpr const_iterator find(const K& k) const; + constexpr size_type count(const key_type& k) const; template - size_type count(const K& k) const; - bool contains(const key_type& k) const; + constexpr size_type count(const K& k) const; + constexpr bool contains(const key_type& k) const; template - bool contains(const K& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + constexpr bool contains(const K& k) const; + constexpr pair equal_range(const key_type& k); + constexpr pair equal_range(const key_type& k) const; template - pair equal_range(const K& k); + constexpr pair equal_range(const K& k); template - pair equal_range(const K& k) const; + constexpr pair equal_range(const K& k) const; // bucket interface - size_type bucket_count() const noexcept; - size_type max_bucket_count() const noexcept; - size_type bucket_size(size_type n) const; - size_type bucket(const key_type& k) const; - template size_type bucket(const K& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - const_local_iterator cbegin(size_type n) const; - const_local_iterator cend(size_type n) const; + constexpr size_type bucket_count() const noexcept; + constexpr size_type max_bucket_count() const noexcept; + constexpr size_type bucket_size(size_type n) const; + constexpr size_type bucket(const key_type& k) const; + template constexpr size_type bucket(const K& k) const; + constexpr local_iterator begin(size_type n); + constexpr const_local_iterator begin(size_type n) const; + constexpr local_iterator end(size_type n); + constexpr const_local_iterator end(size_type n) const; + constexpr const_local_iterator cbegin(size_type n) const; + constexpr const_local_iterator cend(size_type n) const; // hash policy - float load_factor() const noexcept; - float max_load_factor() const noexcept; - void max_load_factor(float z); - void rehash(size_type n); - void reserve(size_type n); + constexpr float load_factor() const noexcept; + constexpr float max_load_factor() const noexcept; + constexpr void max_load_factor(float z); + constexpr void rehash(size_type n); + constexpr void reserve(size_type n); }; template - unordered_set(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_set(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_multiset(from_range_t, R&& rg, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); -unordered_set(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multiset(from_range_t, R&& rg, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +constexpr unordered_set(initializer_list il, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); \end{itemdecl} \begin{itemdescr} @@ -13113,7 +15057,7 @@ \indexlibrarymember{erase_if}{unordered_set}% \begin{itemdecl} template - typename unordered_set::size_type + constexpr typename unordered_set::size_type erase_if(unordered_set& c, Predicate pred); \end{itemdecl} @@ -13138,8 +15082,8 @@ \indexlibrarymember{insert}{unordered_set}% \begin{itemdecl} -template pair insert(K&& obj); -template iterator insert(const_iterator hint, K&& obj); +template constexpr pair insert(K&& obj); +template constexpr iterator insert(const_iterator hint, K&& obj); \end{itemdecl} \begin{itemdescr} @@ -13212,6 +15156,10 @@ are not described in one of the requirement tables, or for which there is additional semantic information. +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. + \indexlibraryglobal{unordered_multiset}% \begin{codeblock} namespace std { @@ -13241,161 +15189,158 @@ using node_type = @\unspec@; // \ref{unord.multiset.cnstr}, construct/copy/destroy - unordered_multiset(); - explicit unordered_multiset(size_type n, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multiset(); + constexpr explicit unordered_multiset(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template - unordered_multiset(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multiset(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_multiset(from_range_t, R&& rg, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); - unordered_multiset(const unordered_multiset&); - unordered_multiset(unordered_multiset&&); - explicit unordered_multiset(const Allocator&); - unordered_multiset(const unordered_multiset&, const type_identity_t&); - unordered_multiset(unordered_multiset&&, const type_identity_t&); - unordered_multiset(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); - unordered_multiset(size_type n, const allocator_type& a) + constexpr unordered_multiset(from_range_t, R&& rg, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + constexpr unordered_multiset(const unordered_multiset&); + constexpr unordered_multiset(unordered_multiset&&); + constexpr explicit unordered_multiset(const Allocator&); + constexpr unordered_multiset(const unordered_multiset&, const type_identity_t&); + constexpr unordered_multiset(unordered_multiset&&, const type_identity_t&); + constexpr unordered_multiset(initializer_list il, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + constexpr unordered_multiset(size_type n, const allocator_type& a) : unordered_multiset(n, hasher(), key_equal(), a) { } - unordered_multiset(size_type n, const hasher& hf, const allocator_type& a) + constexpr unordered_multiset(size_type n, const hasher& hf, const allocator_type& a) : unordered_multiset(n, hf, key_equal(), a) { } template - unordered_multiset(InputIterator f, InputIterator l, size_type n, const allocator_type& a) + constexpr unordered_multiset(InputIterator f, InputIterator l, size_type n, + const allocator_type& a) : unordered_multiset(f, l, n, hasher(), key_equal(), a) { } template - unordered_multiset(InputIterator f, InputIterator l, size_type n, const hasher& hf, - const allocator_type& a) + constexpr unordered_multiset(InputIterator f, InputIterator l, size_type n, + const hasher& hf, const allocator_type& a) : unordered_multiset(f, l, n, hf, key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_multiset(from_range_t, R&& rg, size_type n, const allocator_type& a) + constexpr unordered_multiset(from_range_t, R&& rg, size_type n, const allocator_type& a) : unordered_multiset(from_range, std::forward(rg), n, hasher(), key_equal(), a) { } template<@\exposconcept{container-compatible-range}@ R> - unordered_multiset(from_range_t, R&& rg, size_type n, const hasher& hf, - const allocator_type& a) + constexpr unordered_multiset(from_range_t, R&& rg, size_type n, const hasher& hf, + const allocator_type& a) : unordered_multiset(from_range, std::forward(rg), n, hf, key_equal(), a) { } - unordered_multiset(initializer_list il, size_type n, const allocator_type& a) + constexpr unordered_multiset(initializer_list il, size_type n, + const allocator_type& a) : unordered_multiset(il, n, hasher(), key_equal(), a) { } - unordered_multiset(initializer_list il, size_type n, const hasher& hf, + constexpr unordered_multiset(initializer_list il, size_type n, const hasher& hf, const allocator_type& a) : unordered_multiset(il, n, hf, key_equal(), a) { } - ~unordered_multiset(); - unordered_multiset& operator=(const unordered_multiset&); - unordered_multiset& operator=(unordered_multiset&&) + constexpr ~unordered_multiset(); + constexpr unordered_multiset& operator=(const unordered_multiset&); + constexpr unordered_multiset& operator=(unordered_multiset&&) noexcept(allocator_traits::is_always_equal::value && - is_nothrow_move_assignable_v && - is_nothrow_move_assignable_v); - unordered_multiset& operator=(initializer_list); - allocator_type get_allocator() const noexcept; + is_nothrow_move_assignable_v && is_nothrow_move_assignable_v); + constexpr unordered_multiset& operator=(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; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; // modifiers - template iterator emplace(Args&&... args); - template iterator emplace_hint(const_iterator position, Args&&... args); - iterator insert(const value_type& obj); - iterator insert(value_type&& obj); - iterator insert(const_iterator hint, const value_type& obj); - iterator insert(const_iterator hint, value_type&& obj); - template void insert(InputIterator first, InputIterator last); + template constexpr iterator emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + constexpr iterator insert(const value_type& obj); + constexpr iterator insert(value_type&& obj); + constexpr iterator insert(const_iterator hint, const value_type& obj); + constexpr iterator insert(const_iterator hint, value_type&& obj); + template constexpr void insert(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); - void insert(initializer_list); + constexpr void insert_range(R&& rg); + constexpr void insert(initializer_list); - node_type extract(const_iterator position); - node_type extract(const key_type& x); - template node_type extract(K&& x); - iterator insert(node_type&& nh); - iterator insert(const_iterator hint, node_type&& nh); + constexpr node_type extract(const_iterator position); + constexpr node_type extract(const key_type& x); + template constexpr node_type extract(K&& x); + constexpr iterator insert(node_type&& nh); + constexpr iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position) + constexpr iterator erase(iterator position) requires (!@\libconcept{same_as}@); - iterator erase(const_iterator position); - size_type erase(const key_type& k); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); - void swap(unordered_multiset&) + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& k); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(unordered_multiset&) noexcept(allocator_traits::is_always_equal::value && - is_nothrow_swappable_v && - is_nothrow_swappable_v); - void clear() noexcept; + is_nothrow_swappable_v && is_nothrow_swappable_v); + constexpr void clear() noexcept; template - void merge(unordered_multiset& source); + constexpr void merge(unordered_multiset& source); template - void merge(unordered_multiset&& source); + constexpr void merge(unordered_multiset&& source); template - void merge(unordered_set& source); + constexpr void merge(unordered_set& source); template - void merge(unordered_set&& source); + constexpr void merge(unordered_set&& source); // observers - hasher hash_function() const; - key_equal key_eq() const; + constexpr hasher hash_function() const; + constexpr key_equal key_eq() const; // set operations - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; + constexpr iterator find(const key_type& k); + constexpr const_iterator find(const key_type& k) const; template - iterator find(const K& k); + constexpr iterator find(const K& k); template - const_iterator find(const K& k) const; - size_type count(const key_type& k) const; + constexpr const_iterator find(const K& k) const; + constexpr size_type count(const key_type& k) const; template - size_type count(const K& k) const; - bool contains(const key_type& k) const; + constexpr size_type count(const K& k) const; + constexpr bool contains(const key_type& k) const; template - bool contains(const K& k) const; - pair equal_range(const key_type& k); - pair equal_range(const key_type& k) const; + constexpr bool contains(const K& k) const; + constexpr pair equal_range(const key_type& k); + constexpr pair equal_range(const key_type& k) const; template - pair equal_range(const K& k); + constexpr pair equal_range(const K& k); template - pair equal_range(const K& k) const; + constexpr pair equal_range(const K& k) const; // bucket interface - size_type bucket_count() const noexcept; - size_type max_bucket_count() const noexcept; - size_type bucket_size(size_type n) const; - size_type bucket(const key_type& k) const; - template size_type bucket(const K& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - const_local_iterator cbegin(size_type n) const; - const_local_iterator cend(size_type n) const; + constexpr size_type bucket_count() const noexcept; + constexpr size_type max_bucket_count() const noexcept; + constexpr size_type bucket_size(size_type n) const; + constexpr size_type bucket(const key_type& k) const; + template constexpr size_type bucket(const K& k) const; + constexpr local_iterator begin(size_type n); + constexpr const_local_iterator begin(size_type n) const; + constexpr local_iterator end(size_type n); + constexpr const_local_iterator end(size_type n) const; + constexpr const_local_iterator cbegin(size_type n) const; + constexpr const_local_iterator cend(size_type n) const; // hash policy - float load_factor() const noexcept; - float max_load_factor() const noexcept; - void max_load_factor(float z); - void rehash(size_type n); - void reserve(size_type n); + constexpr float load_factor() const noexcept; + constexpr float max_load_factor() const noexcept; + constexpr void max_load_factor(float z); + constexpr void rehash(size_type n); + constexpr void reserve(size_type n); }; template - unordered_multiset(InputIterator f, InputIterator l, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multiset(InputIterator f, InputIterator l, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); template<@\exposconcept{container-compatible-range}@ R> - unordered_multiset(from_range_t, R&& rg, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); -unordered_multiset(initializer_list il, - size_type n = @\seebelow@, - const hasher& hf = hasher(), - const key_equal& eql = key_equal(), - const allocator_type& a = allocator_type()); + constexpr unordered_multiset(from_range_t, R&& rg, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +constexpr unordered_multiset(initializer_list il, + size_type n = @\seebelow@, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); \end{itemdecl} \begin{itemdescr} @@ -13534,7 +15475,7 @@ \indexlibrarymember{erase_if}{unordered_multiset}% \begin{itemdecl} template - typename unordered_multiset::size_type + constexpr typename unordered_multiset::size_type erase_if(unordered_multiset& c, Predicate pred); \end{itemdecl} @@ -13557,14 +15498,14 @@ \rSec1[container.adaptors]{Container adaptors} -\rSec2[container.adaptors.general]{In general} +\rSec2[container.adaptors.general]{General} \pnum The headers -\libheader{queue}, -\libheader{stack}, -\libheader{flat_map}, -and \libheader{flat_set} +\libheaderref{queue}, +\libheaderref{stack}, +\libheaderrefx{flat_map}{flat.map.syn}, +and \libheaderrefx{flat_set}{flat.set.syn} define the container adaptors \tcode{queue} and \tcode{priority_queue}, \tcode{stack}, @@ -13628,8 +15569,8 @@ \item It has both \tcode{KeyContainer} and \tcode{Compare} template parameters, and \begin{codeblock} is_invocable_v + const typename KeyContainer::value_type&, + const typename KeyContainer::value_type&> \end{codeblock} is not a valid expression or is \tcode{false}. \item It has both \tcode{MappedContainer} and \tcode{Allocator} template parameters, and @@ -13665,23 +15606,24 @@ template> class queue; template - bool operator==(const queue& x, const queue& y); + constexpr bool operator==(const queue& x, const queue& y); template - bool operator!=(const queue& x, const queue& y); + constexpr bool operator!=(const queue& x, const queue& y); template - bool operator< (const queue& x, const queue& y); + constexpr bool operator< (const queue& x, const queue& y); template - bool operator> (const queue& x, const queue& y); + constexpr bool operator> (const queue& x, const queue& y); template - bool operator<=(const queue& x, const queue& y); + constexpr bool operator<=(const queue& x, const queue& y); template - bool operator>=(const queue& x, const queue& y); + constexpr bool operator>=(const queue& x, const queue& y); template - compare_three_way_result_t + constexpr compare_three_way_result_t operator<=>(const queue& x, const queue& y); template - void swap(queue& x, queue& y) noexcept(noexcept(x.swap(y))); + constexpr void swap(queue& x, queue& y) + noexcept(noexcept(x.swap(y))); template struct uses_allocator, Alloc>; @@ -13695,355 +15637,692 @@ class priority_queue; template - void swap(priority_queue& x, - priority_queue& y) noexcept(noexcept(x.swap(y))); + constexpr void swap(priority_queue& x, + priority_queue& y) noexcept(noexcept(x.swap(y))); template struct uses_allocator, Alloc>; - // \ref{container.adaptors.format}, formatter specialization for \tcode{priority_queue} - template Container, class Compare> - struct formatter, charT>; -} -\end{codeblock} + // \ref{container.adaptors.format}, formatter specialization for \tcode{priority_queue} + template Container, class Compare> + struct formatter, charT>; +} +\end{codeblock} + +\rSec2[queue]{Class template \tcode{queue}} + +\rSec3[queue.defn]{Definition} + +\pnum +\indexlibraryglobal{queue}% +Any sequence container supporting operations +\tcode{front()}, +\tcode{back()}, +\tcode{push_back()} +and +\tcode{pop_front()} +can be used to instantiate +\tcode{queue}. +In particular, +\tcode{list}\iref{list} +and +\tcode{deque}\iref{deque} +can be used. + +\begin{codeblock} +namespace std { + template> + class queue { + public: + using value_type = typename Container::value_type; + using reference = typename Container::reference; + using const_reference = typename Container::const_reference; + using size_type = typename Container::size_type; + using container_type = Container; + + protected: + Container c; + + public: + constexpr queue() : queue(Container()) {} + constexpr explicit queue(const Container&); + constexpr explicit queue(Container&&); + template constexpr queue(InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> constexpr queue(from_range_t, R&& rg); + template constexpr explicit queue(const Alloc&); + template constexpr queue(const Container&, const Alloc&); + template constexpr queue(Container&&, const Alloc&); + template constexpr queue(const queue&, const Alloc&); + template constexpr queue(queue&&, const Alloc&); + template + constexpr queue(InputIterator first, InputIterator last, const Alloc&); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr queue(from_range_t, R&& rg, const Alloc&); + + constexpr bool empty() const { return c.empty(); } + constexpr size_type size() const { return c.size(); } + constexpr reference front() { return c.front(); } + constexpr const_reference front() const { return c.front(); } + constexpr reference back() { return c.back(); } + constexpr const_reference back() const { return c.back(); } + constexpr void push(const value_type& x) { c.push_back(x); } + constexpr void push(value_type&& x) { c.push_back(std::move(x)); } + template<@\exposconcept{container-compatible-range}@ R> constexpr void push_range(R&& rg); + template + constexpr decltype(auto) emplace(Args&&... args) + { return c.emplace_back(std::forward(args)...); } + constexpr void pop() { c.pop_front(); } + constexpr void swap(queue& q) noexcept(is_nothrow_swappable_v) + { using std::swap; swap(c, q.c); } + }; + + template + queue(Container) -> queue; + + template + queue(InputIterator, InputIterator) -> queue<@\exposid{iter-value-type}@>; + + template + queue(from_range_t, R&&) -> queue>; + + template + queue(Container, Allocator) -> queue; + + template + queue(InputIterator, InputIterator, Allocator) + -> queue<@\exposid{iter-value-type}@, deque<@\exposid{iter-value-type}@, + Allocator>>; + + template + queue(from_range_t, R&&, Allocator) + -> queue, deque, Allocator>>; + + template + struct uses_allocator, Alloc> + : uses_allocator::type { }; +} +\end{codeblock} + +\rSec3[queue.cons]{Constructors} + +\indexlibraryctor{queue}% +\begin{itemdecl} +constexpr explicit queue(const Container& cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{cont}. +\end{itemdescr} + +\indexlibraryctor{queue}% +\begin{itemdecl} +constexpr explicit queue(Container&& cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{std::move(cont)}. +\end{itemdescr} + +\indexlibraryctor{queue}% +\begin{itemdecl} +template + constexpr queue(InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with +\tcode{first} as the first argument and \tcode{last} as the second argument. +\end{itemdescr} + +\indexlibraryctor{queue}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr queue(from_range_t, R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{ranges::to(std::forward(rg))}. +\end{itemdescr} + +\rSec3[queue.cons.alloc]{Constructors with allocators} + +\pnum +If \tcode{uses_allocator_v} is \tcode{false} +the constructors in this subclause shall not participate in overload resolution. + +\indexlibraryctor{queue}% +\begin{itemdecl} +template constexpr explicit queue(const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{a}. +\end{itemdescr} + +\indexlibraryctor{queue}% +\begin{itemdecl} +template constexpr queue(const container_type& cont, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{cont} as the first argument and \tcode{a} +as the second argument. +\end{itemdescr} + +\indexlibraryctor{queue}% +\begin{itemdecl} +template constexpr queue(container_type&& cont, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{std::move(cont)} as the first argument and \tcode{a} +as the second argument. +\end{itemdescr} + +\indexlibraryctor{queue}% +\begin{itemdecl} +template constexpr queue(const queue& q, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{q.c} as the first argument and \tcode{a} as the +second argument. +\end{itemdescr} + +\indexlibraryctor{queue}% +\begin{itemdecl} +template constexpr queue(queue&& q, const Alloc& a); +\end{itemdecl} -\rSec2[stack.syn]{Header \tcode{} synopsis} +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{std::move(q.c)} as the first argument and \tcode{a} +as the second argument. +\end{itemdescr} -\indexheader{stack}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} +\indexlibraryctor{queue}% +\begin{itemdecl} +template + constexpr queue(InputIterator first, InputIterator last, const Alloc& alloc); +\end{itemdecl} -namespace std { - // \ref{stack}, class template \tcode{stack} - template> class stack; +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with +\tcode{first} as the first argument, +\tcode{last} as the second argument, and +\tcode{alloc} as the third argument. +\end{itemdescr} - template - bool operator==(const stack& x, const stack& y); - template - bool operator!=(const stack& x, const stack& y); - template - bool operator< (const stack& x, const stack& y); - template - bool operator> (const stack& x, const stack& y); - template - 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); +\indexlibraryctor{queue}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr queue(from_range_t, R&& rg, const Alloc& a); +\end{itemdecl} - template - void swap(stack& x, stack& y) noexcept(noexcept(x.swap(y))); - template - struct uses_allocator, Alloc>; +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with +\tcode{ranges::to(std::forward(rg), a)}. +\end{itemdescr} - // \ref{container.adaptors.format}, formatter specialization for \tcode{stack} - template Container> - struct formatter, charT>; -} -\end{codeblock} +\rSec3[queue.mod]{Modifiers} -\rSec2[flat.map.syn]{Header \tcode{} synopsis} +\indexlibrarymember{push_range}{queue}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr void push_range(R&& rg); +\end{itemdecl} -\indexheader{flat_map}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{c.append_range(std::forward(rg))} +if that is a valid expression, +otherwise \tcode{ranges::copy(rg, back_inserter(c))}. +\end{itemdescr} -namespace std { - // \ref{flat.map}, class template \tcode{flat_map} - template, - class KeyContainer = vector, class MappedContainer = vector> - class flat_map; +\rSec3[queue.ops]{Operators} - struct sorted_unique_t { explicit sorted_unique_t() = default; }; - inline constexpr sorted_unique_t sorted_unique{}; +\indexlibrarymember{operator==}{queue}% +\begin{itemdecl} +template + constexpr bool operator==(const queue& x, const queue& y); +\end{itemdecl} - template - struct uses_allocator, - Allocator>; +\begin{itemdescr} +\pnum +\returns +\tcode{x.c == y.c}. +\end{itemdescr} - // \ref{flat.map.erasure}, erasure for \tcode{flat_map} - template - typename flat_map::size_type - erase_if(flat_map& c, Predicate pred); +\indexlibrary{\idxcode{operator"!=}!\idxcode{queue}}% +\begin{itemdecl} +template + constexpr bool operator!=(const queue& x, const queue& y); +\end{itemdecl} - // \ref{flat.multimap}, class template \tcode{flat_multimap} - template, - class KeyContainer = vector, class MappedContainer = vector> - class flat_multimap; +\begin{itemdescr} +\pnum +\returns +\tcode{x.c != y.c}. +\end{itemdescr} - struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; - inline constexpr sorted_equivalent_t sorted_equivalent{}; +\indexlibrarymember{operator<}{queue}% +\begin{itemdecl} +template + constexpr bool operator< (const queue& x, const queue& y); +\end{itemdecl} - template - struct uses_allocator, - Allocator>; +\begin{itemdescr} +\pnum +\returns +\tcode{x.c < y.c}. +\end{itemdescr} - // \ref{flat.multimap.erasure}, erasure for \tcode{flat_multimap} - template - typename flat_multimap::size_type - erase_if(flat_multimap& c, Predicate pred); -} -\end{codeblock} +\indexlibrarymember{operator>}{queue}% +\begin{itemdecl} +template + constexpr bool operator> (const queue& x, const queue& y); +\end{itemdecl} -\rSec2[flat.set.syn]{Header \tcode{} synopsis}% -\indexheader{flat_set}% +\begin{itemdescr} +\pnum +\returns +\tcode{x.c > y.c}. +\end{itemdescr} -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} +\indexlibrarymember{operator<=}{queue}% +\begin{itemdecl} +template + constexpr bool operator<=(const queue& x, const queue& y); +\end{itemdecl} -namespace std { - // \ref{flat.set}, class template \tcode{flat_set} - template, class KeyContainer = vector> - class flat_set; +\begin{itemdescr} +\pnum +\returns +\tcode{x.c <= y.c}. +\end{itemdescr} - struct sorted_unique_t { explicit sorted_unique_t() = default; }; - inline constexpr sorted_unique_t sorted_unique{}; +\indexlibrarymember{operator>=}{queue}% +\begin{itemdecl} +template + constexpr bool operator>=(const queue& x, const queue& y); +\end{itemdecl} - template - struct uses_allocator, Allocator>; +\begin{itemdescr} +\pnum +\returns +\tcode{x.c >= y.c}. +\end{itemdescr} - // \ref{flat.set.erasure}, erasure for \tcode{flat_set} - template - typename flat_set::size_type - erase_if(flat_set& c, Predicate pred); +\indexlibrarymember{operator<=>}{queue}% +\begin{itemdecl} +template + constexpr compare_three_way_result_t + operator<=>(const queue& x, const queue& y); +\end{itemdecl} - // \ref{flat.multiset}, class template \tcode{flat_multiset} - template, class KeyContainer = vector> - class flat_multiset; +\begin{itemdescr} +\pnum +\returns +\tcode{x.c <=> y.c}. +\end{itemdescr} - struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; - inline constexpr sorted_equivalent_t sorted_equivalent{}; +\rSec3[queue.special]{Specialized algorithms} - template - struct uses_allocator, Allocator>; +\indexlibrarymember{swap}{queue}% +\begin{itemdecl} +template + constexpr void swap(queue& x, queue& y) + noexcept(noexcept(x.swap(y))); +\end{itemdecl} - // \ref{flat.multiset.erasure}, erasure for \tcode{flat_multiset} - template - typename flat_multiset::size_type - erase_if(flat_multiset& c, Predicate pred); -} -\end{codeblock} +\begin{itemdescr} +\pnum +\constraints +\tcode{is_swappable_v} is \tcode{true}. -\rSec2[queue]{Class template \tcode{queue}} +\pnum +\effects +As if by \tcode{x.swap(y)}. +\end{itemdescr} -\rSec3[queue.defn]{Definition} +\rSec2[priority.queue]{Class template \tcode{priority_queue}} + +\rSec3[priqueue.overview]{Overview} \pnum -\indexlibraryglobal{queue}% -Any sequence container supporting operations +\indexlibraryglobal{priority_queue}% +Any sequence container with random access iterator and supporting operations \tcode{front()}, -\tcode{back()}, \tcode{push_back()} and -\tcode{pop_front()} +\tcode{pop_back()} can be used to instantiate -\tcode{queue}. +\tcode{priority_queue}. In particular, -\tcode{list}\iref{list} +\tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} can be used. +Instantiating +\tcode{priority_queue} +also involves supplying a function or function object for making +priority comparisons; the library assumes that the function or function +object defines a strict weak ordering\iref{alg.sorting}. \begin{codeblock} namespace std { - template> - class queue { + template, + class Compare = less> + class priority_queue { public: using value_type = typename Container::value_type; using reference = typename Container::reference; using const_reference = typename Container::const_reference; using size_type = typename Container::size_type; - using container_type = Container; + using container_type = Container; + using value_compare = Compare; protected: Container c; + Compare comp; public: - queue() : queue(Container()) {} - explicit queue(const Container&); - explicit queue(Container&&); - template queue(InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> queue(from_range_t, R&& rg); - template explicit queue(const Alloc&); - template queue(const Container&, const Alloc&); - template queue(Container&&, const Alloc&); - template queue(const queue&, const Alloc&); - template queue(queue&&, const Alloc&); + constexpr priority_queue() : priority_queue(Compare()) {} + constexpr explicit priority_queue(const Compare& x) : priority_queue(x, Container()) {} + constexpr priority_queue(const Compare& x, const Container&); + constexpr priority_queue(const Compare& x, Container&&); + template + constexpr priority_queue(InputIterator first, InputIterator last, + const Compare& x = Compare()); + template + constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x, + const Container&); + template + constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x, + Container&&); + template<@\exposconcept{container-compatible-range}@ R> + constexpr priority_queue(from_range_t, R&& rg, const Compare& x = Compare()); + template constexpr explicit priority_queue(const Alloc&); + template constexpr priority_queue(const Compare&, const Alloc&); + template + constexpr priority_queue(const Compare&, const Container&, const Alloc&); + template constexpr priority_queue(const Compare&, Container&&, const Alloc&); + template constexpr priority_queue(const priority_queue&, const Alloc&); + template constexpr priority_queue(priority_queue&&, const Alloc&); template - queue(InputIterator first, InputIterator last, const Alloc&); - template<@\exposconcept{container-compatible-range}@ R, class Alloc> - queue(from_range_t, R&& rg, const Alloc&); - - [[nodiscard]] bool empty() const { return c.empty(); } - size_type size() const { return c.size(); } - reference front() { return c.front(); } - const_reference front() const { return c.front(); } - reference back() { return c.back(); } - const_reference back() const { return c.back(); } - void push(const value_type& x) { c.push_back(x); } - void push(value_type&& x) { c.push_back(std::move(x)); } - template<@\exposconcept{container-compatible-range}@ R> void push_range(R&& rg); - template - decltype(auto) emplace(Args&&... args) - { return c.emplace_back(std::forward(args)...); } - void pop() { c.pop_front(); } - void swap(queue& q) noexcept(is_nothrow_swappable_v) - { using std::swap; swap(c, q.c); } + constexpr priority_queue(InputIterator, InputIterator, const Alloc&); + template + constexpr priority_queue(InputIterator, InputIterator, const Compare&, const Alloc&); + template + constexpr priority_queue(InputIterator, InputIterator, const Compare&, const Container&, + const Alloc&); + template + constexpr priority_queue(InputIterator, InputIterator, const Compare&, Container&&, + const Alloc&); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr priority_queue(from_range_t, R&& rg, const Compare&, const Alloc&); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr priority_queue(from_range_t, R&& rg, const Alloc&); + + constexpr bool empty() const { return c.empty(); } + constexpr size_type size() const { return c.size(); } + constexpr const_reference top() const { return c.front(); } + constexpr void push(const value_type& x); + constexpr void push(value_type&& x); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void push_range(R&& rg); + template constexpr void emplace(Args&&... args); + constexpr void pop(); + constexpr void swap(priority_queue& q) + noexcept(is_nothrow_swappable_v && is_nothrow_swappable_v) + { using std::swap; swap(c, q.c); swap(comp, q.comp); } }; - template - queue(Container) -> queue; + template + priority_queue(Compare, Container) + -> priority_queue; - template - queue(InputIterator, InputIterator) -> queue<@\exposid{iter-value-type}@>; + template>, + class Container = vector<@\exposid{iter-value-type}@>> + priority_queue(InputIterator, InputIterator, Compare = Compare(), Container = Container()) + -> priority_queue<@\exposid{iter-value-type}@, Container, Compare>; - template - queue(from_range_t, R&&) -> queue>; + template>> + priority_queue(from_range_t, R&&, Compare = Compare()) + -> priority_queue, vector>, Compare>; - template - queue(Container, Allocator) -> queue; + template + priority_queue(Compare, Container, Allocator) + -> priority_queue; template - queue(InputIterator, InputIterator, Allocator) - -> queue<@\exposid{iter-value-type}@, deque<@\exposid{iter-value-type}@, - Allocator>>; + priority_queue(InputIterator, InputIterator, Allocator) + -> priority_queue<@\exposid{iter-value-type}@, + vector<@\exposid{iter-value-type}@, Allocator>, + less<@\exposid{iter-value-type}@>>; + + template + priority_queue(InputIterator, InputIterator, Compare, Allocator) + -> priority_queue<@\exposid{iter-value-type}@, + vector<@\exposid{iter-value-type}@, Allocator>, Compare>; + + template + priority_queue(InputIterator, InputIterator, Compare, Container, Allocator) + -> priority_queue; + + template + priority_queue(from_range_t, R&&, Compare, Allocator) + -> priority_queue, vector, Allocator>, + Compare>; template - queue(from_range_t, R&&, Allocator) - -> queue, deque, Allocator>>; + priority_queue(from_range_t, R&&, Allocator) + -> priority_queue, vector, Allocator>>; - template - struct uses_allocator, Alloc> + // no equality is provided + + template + struct uses_allocator, Alloc> : uses_allocator::type { }; } \end{codeblock} -\rSec3[queue.cons]{Constructors} +\rSec3[priqueue.cons]{Constructors} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -explicit queue(const Container& cont); +constexpr priority_queue(const Compare& x, const Container& y); +constexpr priority_queue(const Compare& x, Container&& y); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{x} defines a strict weak ordering\iref{alg.sorting}. + \pnum \effects -Initializes \tcode{c} with \tcode{cont}. +Initializes +\tcode{comp} with +\tcode{x} and +\tcode{c} with +\tcode{y} (copy constructing or move constructing as appropriate); +calls +\tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -explicit queue(Container&& cont); +template + constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x = Compare()); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{x} defines a strict weak ordering\iref{alg.sorting}. + \pnum \effects -Initializes \tcode{c} with \tcode{std::move(cont)}. +Initializes \tcode{c} with +\tcode{first} as the first argument and +\tcode{last} as the second argument, and +initializes \tcode{comp} with \tcode{x}; +then calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} template - queue(InputIterator first, InputIterator last); + constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x, + const Container& y); +template + constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x, + Container&& y); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{x} defines a strict weak ordering\iref{alg.sorting}. + \pnum \effects -Initializes \tcode{c} with -\tcode{first} as the first argument and \tcode{last} as the second argument. +Initializes +\tcode{comp} with +\tcode{x} and +\tcode{c} with +\tcode{y} (copy constructing or move constructing as appropriate); +calls +\tcode{c.insert(c.end(), first, last)}; +and finally calls +\tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - queue(from_range_t, R&& rg); + constexpr priority_queue(from_range_t, R&& rg, const Compare& x = Compare()); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{x} defines a strict weak ordering\iref{alg.sorting}. + \pnum \effects -Initializes \tcode{c} with \tcode{ranges::to(std::forward(rg))}. +Initializes \tcode{comp} with \tcode{x} and +\tcode{c} with \tcode{ranges::to(std::forward(rg))} and +finally calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\rSec3[queue.cons.alloc]{Constructors with allocators} +\rSec3[priqueue.cons.alloc]{Constructors with allocators} \pnum If \tcode{uses_allocator_v} is \tcode{false} the constructors in this subclause shall not participate in overload resolution. -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template explicit queue(const Alloc& a); +template constexpr explicit priority_queue(const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \tcode{c} with \tcode{a}. +Initializes \tcode{c} with \tcode{a} and value-initializes \tcode{comp}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template queue(const container_type& cont, const Alloc& a); +template constexpr priority_queue(const Compare& compare, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \tcode{c} with \tcode{cont} as the first argument and \tcode{a} -as the second argument. +Initializes \tcode{c} with \tcode{a} and initializes \tcode{comp} with \tcode{compare}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template queue(container_type&& cont, const Alloc& a); +template + constexpr priority_queue(const Compare& compare, const Container& cont, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{cont} as the first argument and \tcode{a} as the second +argument, and initializes \tcode{comp} with \tcode{compare}; +calls \tcode{make_heap(c.begin(), c.end(), comp)}. +\end{itemdescr} + +\indexlibraryctor{priority_queue}% +\begin{itemdecl} +template + constexpr priority_queue(const Compare& compare, Container&& cont, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{c} with \tcode{std::move(cont)} as the first argument and \tcode{a} -as the second argument. +as the second argument, and initializes \tcode{comp} with \tcode{compare}; +calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template queue(const queue& q, const Alloc& a); +template constexpr priority_queue(const priority_queue& q, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \tcode{c} with \tcode{q.c} as the first argument and \tcode{a} as the -second argument. +Initializes \tcode{c} with \tcode{q.c} as the first argument and \tcode{a} as +the second argument, and initializes \tcode{comp} with \tcode{q.comp}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template queue(queue&& q, const Alloc& a); +template constexpr priority_queue(priority_queue&& q, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{c} with \tcode{std::move(q.c)} as the first argument and \tcode{a} -as the second argument. +as the second argument, and initializes \tcode{comp} with \tcode{std::move(q.comp)}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} template - queue(InputIterator first, InputIterator last, const Alloc& alloc); + constexpr priority_queue(InputIterator first, InputIterator last, const Alloc& a); \end{itemdecl} \begin{itemdescr} @@ -14052,2167 +16331,2422 @@ Initializes \tcode{c} with \tcode{first} as the first argument, \tcode{last} as the second argument, and -\tcode{alloc} as the third argument. +\tcode{a} as the third argument, and +value-initializes \tcode{comp}; +calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\indexlibraryctor{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R, class Alloc> - queue(from_range_t, R&& rg, const Alloc& a); +template + constexpr priority_queue(InputIterator first, InputIterator last, + const Compare& compare, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{c} with -\tcode{ranges::to(std::forward(rg), a)}. +\tcode{first} as the first argument, +\tcode{last} as the second argument, and +\tcode{a} as the third argument, and +initializes \tcode{comp} with \tcode{compare}; +calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\rSec3[queue.mod]{Modifiers} - -\indexlibrarymember{push_range}{queue}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - void push_range(R&& rg); +template + constexpr priority_queue(InputIterator first, InputIterator last, const Compare& compare, + const Container& cont, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{c.append_range(std::forward(rg))} -if that is a valid expression, -otherwise \tcode{ranges::copy(rg, back_inserter(c))}. +Initializes \tcode{c} with +\tcode{cont} as the first argument and \tcode{a} as the second argument, and +initializes \tcode{comp} with \tcode{compare}; +calls \tcode{c.insert(c.end(), first, last)}; and +finally calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\rSec3[queue.ops]{Operators} +\indexlibraryctor{priority_queue}% +\begin{itemdecl} +template + constexpr priority_queue(InputIterator first, InputIterator last, const Compare& compare, + Container&& cont, const Alloc& a); +\end{itemdecl} -\indexlibrarymember{operator==}{queue}% +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with +\tcode{std::move(cont)} as the first argument and +\tcode{a} as the second argument, and +initializes \tcode{comp} with \tcode{compare}; +calls \tcode{c.insert(c.end(), first, last)}; and +finally calls \tcode{make_heap(c.begin(), c.end(), comp)}. +\end{itemdescr} + +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template - bool operator==(const queue& x, const queue& y); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr priority_queue(from_range_t, R&& rg, const Compare& compare, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c == y.c}. +\effects +Initializes \tcode{comp} with \tcode{compare} and +\tcode{c} with \tcode{ranges::to(std::forward(rg), a)}; +calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{queue}}% +\indexlibraryctor{priority_queue}% \begin{itemdecl} -template - bool operator!=(const queue& x, const queue& y); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr priority_queue(from_range_t, R&& rg, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c != y.c}. +\effects +Initializes +\tcode{c} with \tcode{ranges::to(std::forward(rg), a)} +and value-initializes \tcode{comp}; +calls \tcode{make_heap(c.begin(), c.end(), comp)}. \end{itemdescr} -\indexlibrarymember{operator<}{queue}% +\rSec3[priqueue.members]{Members} + +\indexlibrarymember{push}{priority_queue}% \begin{itemdecl} -template - bool operator< (const queue& x, const queue& y); +constexpr void push(const value_type& x); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c < y.c}. +\effects +As if by: +\begin{codeblock} +c.push_back(x); +push_heap(c.begin(), c.end(), comp); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator>}{queue}% +\indexlibrarymember{push}{priority_queue}% \begin{itemdecl} -template - bool operator> (const queue& x, const queue& y); +constexpr void push(value_type&& x); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c > y.c}. +\effects +As if by: +\begin{codeblock} +c.push_back(std::move(x)); +push_heap(c.begin(), c.end(), comp); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator<=}{queue}% +\indexlibrarymember{push_range}{priority_queue}% \begin{itemdecl} -template - bool operator<=(const queue& x, const queue& y); +template<@\exposconcept{container-compatible-range}@ R> + constexpr void push_range(R&& rg); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c <= y.c}. +\effects +Inserts all elements of \tcode{rg} in \tcode{c} via +\tcode{c.append_range(std::forward(rg))} if that is a valid expression, or +\tcode{ranges::copy(rg, back_inserter(c))} otherwise. +Then restores the heap property as if by +\tcode{make_heap(c.begin(), c.end(), comp)}. + +\pnum +\ensures +\tcode{is_heap(c.begin(), c.end(), comp)} is \tcode{true}. \end{itemdescr} -\indexlibrarymember{operator>=}{queue}% +\indexlibrarymember{emplace}{priority_queue}% \begin{itemdecl} -template - bool operator>=(const queue& x, - const queue& y); +template constexpr void emplace(Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c >= y.c}. +\effects +As if by: +\begin{codeblock} +c.emplace_back(std::forward(args)...); +push_heap(c.begin(), c.end(), comp); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator<=>}{queue}% +\indexlibrarymember{pop}{priority_queue}% \begin{itemdecl} -template - compare_three_way_result_t - operator<=>(const queue& x, const queue& y); +constexpr void pop(); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c <=> y.c}. +\effects +As if by: +\begin{codeblock} +pop_heap(c.begin(), c.end(), comp); +c.pop_back(); +\end{codeblock} \end{itemdescr} -\rSec3[queue.special]{Specialized algorithms} +\rSec3[priqueue.special]{Specialized algorithms} -\indexlibrarymember{swap}{queue}% +\indexlibrarymember{swap}{priority_queue}% \begin{itemdecl} -template - void swap(queue& x, queue& y) noexcept(noexcept(x.swap(y))); +template + constexpr void swap(priority_queue& x, + priority_queue& y) noexcept(noexcept(x.swap(y))); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_swappable_v} is \tcode{true}. +\tcode{is_swappable_v} is \tcode{true} and +\tcode{is_swappable_v} is \tcode{true}. \pnum \effects As if by \tcode{x.swap(y)}. \end{itemdescr} -\rSec2[priority.queue]{Class template \tcode{priority_queue}} +\rSec2[stack.syn]{Header \tcode{} synopsis} -\rSec3[priqueue.overview]{Overview} +\indexheader{stack}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{stack}, class template \tcode{stack} + template> class stack; + + template + constexpr bool operator==(const stack& x, const stack& y); + template + constexpr bool operator!=(const stack& x, const stack& y); + template + constexpr bool operator< (const stack& x, const stack& y); + template + constexpr bool operator> (const stack& x, const stack& y); + template + constexpr bool operator<=(const stack& x, const stack& y); + template + constexpr bool operator>=(const stack& x, const stack& y); + template + constexpr compare_three_way_result_t + operator<=>(const stack& x, const stack& y); + + template + constexpr void swap(stack& x, stack& y) + noexcept(noexcept(x.swap(y))); + template + struct uses_allocator, Alloc>; + + // \ref{container.adaptors.format}, formatter specialization for \tcode{stack} + template Container> + struct formatter, charT>; +} +\end{codeblock} + +\rSec2[stack]{Class template \tcode{stack}} + +\rSec3[stack.general]{General} \pnum -\indexlibraryglobal{priority_queue}% -Any sequence container with random access iterator and supporting operations -\tcode{front()}, +\indexlibraryglobal{stack}% +Any sequence container supporting operations +\tcode{back()}, \tcode{push_back()} and \tcode{pop_back()} can be used to instantiate -\tcode{priority_queue}. +\tcode{stack}. In particular, -\tcode{vector}\iref{vector} +\tcode{vector}\iref{vector}, +\tcode{list}\iref{list} and \tcode{deque}\iref{deque} can be used. -Instantiating -\tcode{priority_queue} -also involves supplying a function or function object for making -priority comparisons; the library assumes that the function or function -object defines a strict weak ordering\iref{alg.sorting}. + +\rSec3[stack.defn]{Definition} \begin{codeblock} namespace std { - template, - class Compare = less> - class priority_queue { + template> + class stack { public: using value_type = typename Container::value_type; using reference = typename Container::reference; using const_reference = typename Container::const_reference; using size_type = typename Container::size_type; using container_type = Container; - using value_compare = Compare; protected: Container c; - Compare comp; public: - priority_queue() : priority_queue(Compare()) {} - explicit priority_queue(const Compare& x) : priority_queue(x, Container()) {} - priority_queue(const Compare& x, const Container&); - priority_queue(const Compare& x, Container&&); - template - priority_queue(InputIterator first, InputIterator last, const Compare& x = Compare()); - template - priority_queue(InputIterator first, InputIterator last, const Compare& x, - const Container&); - template - priority_queue(InputIterator first, InputIterator last, const Compare& x, - Container&&); + constexpr stack() : stack(Container()) {} + constexpr explicit stack(const Container&); + constexpr explicit stack(Container&&); + template constexpr stack(InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - priority_queue(from_range_t, R&& rg, const Compare& x = Compare()); - template explicit priority_queue(const Alloc&); - template priority_queue(const Compare&, const Alloc&); - template priority_queue(const Compare&, const Container&, const Alloc&); - template priority_queue(const Compare&, Container&&, const Alloc&); - template priority_queue(const priority_queue&, const Alloc&); - template priority_queue(priority_queue&&, const Alloc&); - template - priority_queue(InputIterator, InputIterator, const Alloc&); + constexpr stack(from_range_t, R&& rg); + template constexpr explicit stack(const Alloc&); + template constexpr stack(const Container&, const Alloc&); + template constexpr stack(Container&&, const Alloc&); + template constexpr stack(const stack&, const Alloc&); + template constexpr stack(stack&&, const Alloc&); template - priority_queue(InputIterator, InputIterator, const Compare&, const Alloc&); - template - priority_queue(InputIterator, InputIterator, const Compare&, const Container&, - const Alloc&); - template - priority_queue(InputIterator, InputIterator, const Compare&, Container&&, const Alloc&); + constexpr stack(InputIterator first, InputIterator last, const Alloc&); template<@\exposconcept{container-compatible-range}@ R, class Alloc> - priority_queue(from_range_t, R&& rg, const Compare&, const Alloc&); - template<@\exposconcept{container-compatible-range}@ R, class Alloc> - priority_queue(from_range_t, R&& rg, const Alloc&); - - [[nodiscard]] bool empty() const { return c.empty(); } - size_type size() const { return c.size(); } - const_reference top() const { return c.front(); } - void push(const value_type& x); - void push(value_type&& x); + constexpr stack(from_range_t, R&& rg, const Alloc&); + + constexpr bool empty() const { return c.empty(); } + constexpr size_type size() const { return c.size(); } + constexpr reference top() { return c.back(); } + constexpr const_reference top() const { return c.back(); } + constexpr void push(const value_type& x) { c.push_back(x); } + constexpr void push(value_type&& x) { c.push_back(std::move(x)); } template<@\exposconcept{container-compatible-range}@ R> - void push_range(R&& rg); - template void emplace(Args&&... args); - void pop(); - void swap(priority_queue& q) noexcept(is_nothrow_swappable_v && - is_nothrow_swappable_v) - { using std::swap; swap(c, q.c); swap(comp, q.comp); } + constexpr void push_range(R&& rg); + template + constexpr decltype(auto) emplace(Args&&... args) + { return c.emplace_back(std::forward(args)...); } + constexpr void pop() { c.pop_back(); } + constexpr void swap(stack& s) noexcept(is_nothrow_swappable_v) + { using std::swap; swap(c, s.c); } }; - template - priority_queue(Compare, Container) - -> priority_queue; + template + stack(Container) -> stack; - template>, - class Container = vector<@\exposid{iter-value-type}@>> - priority_queue(InputIterator, InputIterator, Compare = Compare(), Container = Container()) - -> priority_queue<@\exposid{iter-value-type}@, Container, Compare>; + template + stack(InputIterator, InputIterator) -> stack<@\exposid{iter-value-type}@>; - template>> - priority_queue(from_range_t, R&&, Compare = Compare()) - -> priority_queue, vector>, Compare>; + template + stack(from_range_t, R&&) -> stack>; - template - priority_queue(Compare, Container, Allocator) - -> priority_queue; + template + stack(Container, Allocator) -> stack; template - priority_queue(InputIterator, InputIterator, Allocator) - -> priority_queue<@\exposid{iter-value-type}@, - vector<@\exposid{iter-value-type}@, Allocator>, - less<@\exposid{iter-value-type}@>>; - - template - priority_queue(InputIterator, InputIterator, Compare, Allocator) - -> priority_queue<@\exposid{iter-value-type}@, - vector<@\exposid{iter-value-type}@, Allocator>, Compare>; - - template - priority_queue(InputIterator, InputIterator, Compare, Container, Allocator) - -> priority_queue; - - template - priority_queue(from_range_t, R&&, Compare, Allocator) - -> priority_queue, vector, Allocator>, - Compare>; + stack(InputIterator, InputIterator, Allocator) + -> stack<@\exposid{iter-value-type}@, deque<@\exposid{iter-value-type}@, + Allocator>>; template - priority_queue(from_range_t, R&&, Allocator) - -> priority_queue, vector, Allocator>>; - - // no equality is provided + stack(from_range_t, R&&, Allocator) + -> stack, deque, Allocator>>; - template - struct uses_allocator, Alloc> + template + struct uses_allocator, Alloc> : uses_allocator::type { }; } \end{codeblock} -\rSec3[priqueue.cons]{Constructors} +\rSec3[stack.cons]{Constructors} -\indexlibraryctor{priority_queue}% +\indexlibraryctor{stack}% \begin{itemdecl} -priority_queue(const Compare& x, const Container& y); -priority_queue(const Compare& x, Container&& y); +constexpr explicit stack(const Container& cont); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{x} defines a strict weak ordering\iref{alg.sorting}. +\effects +Initializes \tcode{c} with \tcode{cont}. +\end{itemdescr} + +\indexlibraryctor{stack}% +\begin{itemdecl} +constexpr explicit stack(Container&& cont); +\end{itemdecl} +\begin{itemdescr} \pnum \effects -Initializes -\tcode{comp} with -\tcode{x} and -\tcode{c} with -\tcode{y} (copy constructing or move constructing as appropriate); -calls -\tcode{make_heap(c.begin(), c.end(), comp)}. +Initializes \tcode{c} with \tcode{std::move(cont)}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibraryctor{stack}% +\begin{itemdecl} +template + constexpr stack(InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with +\tcode{first} as the first argument and \tcode{last} as the second argument. +\end{itemdescr} + +\indexlibraryctor{stack}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr stack(from_range_t, R&& rg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{ranges::to(std::forward(rg))}. +\end{itemdescr} + +\rSec3[stack.cons.alloc]{Constructors with allocators} + +\pnum +If \tcode{uses_allocator_v} is \tcode{false} +the constructors in this subclause shall not participate in overload resolution. + +\indexlibraryctor{stack}% +\begin{itemdecl} +template constexpr explicit stack(const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{a}. +\end{itemdescr} + +\indexlibraryctor{stack}% +\begin{itemdecl} +template constexpr stack(const container_type& cont, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{cont} as the first argument and \tcode{a} as the +second argument. +\end{itemdescr} + +\indexlibraryctor{stack}% +\begin{itemdecl} +template constexpr stack(container_type&& cont, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{std::move(cont)} as the first argument and \tcode{a} +as the second argument. +\end{itemdescr} + +\indexlibraryctor{stack}% +\begin{itemdecl} +template constexpr stack(const stack& s, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c} with \tcode{s.c} as the first argument and \tcode{a} +as the second argument. +\end{itemdescr} + +\indexlibraryctor{stack}% \begin{itemdecl} -template - priority_queue(InputIterator first, InputIterator last, const Compare& x = Compare()); +template constexpr stack(stack&& s, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{x} defines a strict weak ordering\iref{alg.sorting}. +\effects +Initializes \tcode{c} with \tcode{std::move(s.c)} as the first argument and \tcode{a} +as the second argument. +\end{itemdescr} +\indexlibraryctor{stack}% +\begin{itemdecl} +template + constexpr stack(InputIterator first, InputIterator last, const Alloc& alloc); +\end{itemdecl} + +\begin{itemdescr} \pnum \effects Initializes \tcode{c} with -\tcode{first} as the first argument and +\tcode{first} as the first argument, \tcode{last} as the second argument, and -initializes \tcode{comp} with \tcode{x}; -then calls \tcode{make_heap(c.begin(), c.end(), comp)}. +\tcode{alloc} as the third argument. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibraryctor{stack}% \begin{itemdecl} -template - priority_queue(InputIterator first, InputIterator last, const Compare& x, const Container& y); -template - priority_queue(InputIterator first, InputIterator last, const Compare& x, Container&& y); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr stack(from_range_t, R&& rg, const Alloc& a); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{x} defines a strict weak ordering\iref{alg.sorting}. - \pnum \effects Initializes -\tcode{comp} with -\tcode{x} and -\tcode{c} with -\tcode{y} (copy constructing or move constructing as appropriate); -calls -\tcode{c.insert(c.end(), first, last)}; -and finally calls -\tcode{make_heap(c.begin(), c.end(), comp)}. +\tcode{c} with \tcode{ranges::to(std::forward(rg), a)}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\rSec3[stack.mod]{Modifiers} + +\indexlibrarymember{push_range}{stack}% \begin{itemdecl} template<@\exposconcept{container-compatible-range}@ R> - priority_queue(from_range_t, R&& rg, const Compare& x = Compare()); + constexpr void push_range(R&& rg); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{x} defines a strict weak ordering\iref{alg.sorting}. - \pnum \effects -Initializes \tcode{comp} with \tcode{x} and -\tcode{c} with \tcode{ranges::to(std::forward(rg))} and -finally calls \tcode{make_heap(c.begin(), c.end(), comp)}. +Equivalent to \tcode{c.append_range(std::forward(rg))} +if that is a valid expression, +otherwise \tcode{ranges::copy(rg, back_inserter(c))}. \end{itemdescr} -\rSec3[priqueue.cons.alloc]{Constructors with allocators} - -\pnum -If \tcode{uses_allocator_v} is \tcode{false} -the constructors in this subclause shall not participate in overload resolution. +\rSec3[stack.ops]{Operators} -\indexlibraryctor{priority_queue}% +\indexlibrarymember{operator==}{stack}% \begin{itemdecl} -template explicit priority_queue(const Alloc& a); +template + constexpr bool operator==(const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{a} and value-initializes \tcode{comp}. +\returns +\tcode{x.c == y.c}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibrary{\idxcode{operator"!=}!\idxcode{stack}}% \begin{itemdecl} -template priority_queue(const Compare& compare, const Alloc& a); +template + constexpr bool operator!=(const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{a} and initializes \tcode{comp} with \tcode{compare}. +\returns +\tcode{x.c != y.c}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibrarymember{operator<}{stack}% \begin{itemdecl} -template - priority_queue(const Compare& compare, const Container& cont, const Alloc& a); +template + constexpr bool operator< (const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{cont} as the first argument and \tcode{a} as the second -argument, and initializes \tcode{comp} with \tcode{compare}; -calls \tcode{make_heap(c.begin(), c.end(), comp)}. +\returns +\tcode{x.c < y.c}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibrarymember{operator>}{stack}% \begin{itemdecl} -template - priority_queue(const Compare& compare, Container&& cont, const Alloc& a); +template + constexpr bool operator> (const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{std::move(cont)} as the first argument and \tcode{a} -as the second argument, and initializes \tcode{comp} with \tcode{compare}; -calls \tcode{make_heap(c.begin(), c.end(), comp)}. +\returns +\tcode{x.c > y.c}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibrarymember{operator<=}{stack}% \begin{itemdecl} -template priority_queue(const priority_queue& q, const Alloc& a); +template + constexpr bool operator<=(const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{q.c} as the first argument and \tcode{a} as -the second argument, and initializes \tcode{comp} with \tcode{q.comp}. +\returns +\tcode{x.c <= y.c}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibrarymember{operator>=}{stack}% \begin{itemdecl} -template priority_queue(priority_queue&& q, const Alloc& a); +template + constexpr bool operator>=(const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{std::move(q.c)} as the first argument and \tcode{a} -as the second argument, and initializes \tcode{comp} with \tcode{std::move(q.comp)}. +\returns +\tcode{x.c >= y.c}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\indexlibrarymember{operator<=>}{stack}% \begin{itemdecl} -template - priority_queue(InputIterator first, InputIterator last, const Alloc& a); +template + constexpr compare_three_way_result_t + operator<=>(const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with -\tcode{first} as the first argument, -\tcode{last} as the second argument, and -\tcode{a} as the third argument, and -value-initializes \tcode{comp}; -calls \tcode{make_heap(c.begin(), c.end(), comp)}. +\returns +\tcode{x.c <=> y.c}. \end{itemdescr} -\indexlibraryctor{priority_queue}% +\rSec3[stack.special]{Specialized algorithms} + +\indexlibrarymember{swap}{stack}% \begin{itemdecl} -template - priority_queue(InputIterator first, InputIterator last, const Compare& compare, const Alloc& a); +template + constexpr void swap(stack& x, stack& y) + noexcept(noexcept(x.swap(y))); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{is_swappable_v} is \tcode{true}. + \pnum \effects -Initializes \tcode{c} with -\tcode{first} as the first argument, -\tcode{last} as the second argument, and -\tcode{a} as the third argument, and -initializes \tcode{comp} with \tcode{compare}; -calls \tcode{make_heap(c.begin(), c.end(), comp)}. +As if by \tcode{x.swap(y)}. \end{itemdescr} -\indexlibraryctor{priority_queue}% -\begin{itemdecl} -template - priority_queue(InputIterator first, InputIterator last, const Compare& compare, - const Container& cont, const Alloc& a); -\end{itemdecl} +\rSec2[flat.map.syn]{Header \tcode{} synopsis} + +\indexheader{flat_map}% +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{flat.map}, class template \tcode{flat_map} + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_map; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, + Allocator>; + + // \ref{flat.map.erasure}, erasure for \tcode{flat_map} + template + constexpr typename flat_map::size_type + erase_if(flat_map& c, Predicate pred); + + // \ref{flat.multimap}, class template \tcode{flat_multimap} + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_multimap; + + struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; + inline constexpr sorted_equivalent_t sorted_equivalent{}; + + template + struct uses_allocator, + Allocator>; + + // \ref{flat.multimap.erasure}, erasure for \tcode{flat_multimap} + template + constexpr typename flat_multimap::size_type + erase_if(flat_multimap& c, Predicate pred); +} +\end{codeblock} + +\rSec2[flat.map]{Class template \tcode{flat_map}} + +\rSec3[flat.map.overview]{Overview} -\begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with -\tcode{cont} as the first argument and \tcode{a} as the second argument, and -initializes \tcode{comp} with \tcode{compare}; -calls \tcode{c.insert(c.end(), first, last)}; and -finally calls \tcode{make_heap(c.begin(), c.end(), comp)}. -\end{itemdescr} +\indexlibraryglobal{flat_map}% +A \tcode{flat_map} is a container adaptor +that provides an associative container interface +that supports unique keys +(i.e., contains at most one of each key value) and +provides for fast retrieval of values of another type \tcode{T} +based on the keys. +\tcode{flat_map} supports iterators +that meet the \oldconcept{InputIterator} requirements and +model the +\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. -\indexlibraryctor{priority_queue}% -\begin{itemdecl} -template - priority_queue(InputIterator first, InputIterator last, const Compare& compare, Container&& cont, - const Alloc& a); -\end{itemdecl} +\pnum +A \tcode{flat_map} meets all of the requirements +of a container\iref{container.reqmts} and +of a reversible container\iref{container.rev.reqmts}, +plus the optional container requirements\iref{container.opt.reqmts}. +\tcode{flat_map} meets the requirements of +an associative container\iref{associative.reqmts}, +except that: +\begin{itemize} +\item +it does not meet the requirements related to node handles\iref{container.node}, +\item +it does not meet the requirements related to iterator invalidation, and +\item +the time complexity of the operations that insert or erase a single +element from the map is linear, including the ones that take an insertion +position iterator. +\end{itemize} +\begin{note} +A \tcode{flat_map} does not meet the additional requirements of +an allocator-aware container\iref{container.alloc.reqmts}. +\end{note} + +\pnum +A \tcode{flat_map} also provides most operations +described in \ref{associative.reqmts} for unique keys. +This means that a \tcode{flat_map} supports +the \tcode{a_uniq} operations in \ref{associative.reqmts} +but not the \tcode{a_eq} operations. +For a \tcode{flat_map} +the \tcode{key_type} is \tcode{Key} and +the \tcode{value_type} is \tcode{pair}. + +\pnum +Descriptions are provided here only for operations on \tcode{flat_map} that +are not described in one of those sets of requirements or for operations where +there is additional semantic information. + +\pnum +A \tcode{flat_map} maintains the following invariants: +\begin{itemize} +\item +it contains the same number of keys and values; +\item +the keys are sorted with respect to the comparison object; and +\item +the value at offset \tcode{off} within the value container is +the value associated with the key at offset \tcode{off} +within the key container. +\end{itemize} -\begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with -\tcode{std::move(cont)} as the first argument and -\tcode{a} as the second argument, and -initializes \tcode{comp} with \tcode{compare}; -calls \tcode{c.insert(c.end(), first, last)}; and -finally calls \tcode{make_heap(c.begin(), c.end(), comp)}. -\end{itemdescr} +If any member function in \ref{flat.map.defn} exits via an exception +the invariants are restored. +\begin{note} +This can result in the \tcode{flat_map} being emptied. +\end{note} -\indexlibraryctor{priority_queue}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R, class Alloc> - priority_queue(from_range_t, R&& rg, const Compare& compare, const Alloc& a); -\end{itemdecl} +\pnum +Any type \tcode{C} +that meets the sequence container requirements\iref{sequence.reqmts} +can be used to instantiate \tcode{flat_map}, +as long as +\tcode{C::iterator} meets the \oldconcept{RandomAccessIterator} requirements and +invocations of +member functions \tcode{C::size} and \tcode{C::max_size} do not exit via an exception. +In particular, \tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} +can be used. +\begin{note} +\tcode{vector} is not a sequence container. +\end{note} -\begin{itemdescr} \pnum -\effects -Initializes \tcode{comp} with \tcode{compare} and -\tcode{c} with \tcode{ranges::to(std::forward(rg), a)}; -calls \tcode{make_heap(c.begin(), c.end(), comp)}. -\end{itemdescr} +The program is ill-formed if +\tcode{Key} is not the same type as \tcode{KeyContainer::value_type} or +\tcode{T} is not the same type as \tcode{MappedContainer::value_type}. -\indexlibraryctor{priority_queue}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R, class Alloc> - priority_queue(from_range_t, R&& rg, const Alloc& a); -\end{itemdecl} +\pnum +The effect of calling a constructor +that takes +both \tcode{key_container_type} and \tcode{mapped_container_type} arguments with +containers of different sizes is undefined. -\begin{itemdescr} \pnum -\effects -Initializes -\tcode{c} with \tcode{ranges::to(std::forward(rg), a)}; -calls \tcode{make_heap(c.\linebreak begin(), c.end(), comp)}. -\end{itemdescr} +The effect of calling a constructor or member function +that takes a \tcode{sorted_unique_t} argument with +a container, containers, or range +that is not sorted with respect to \tcode{key_comp()}, or +that contains equal elements, +is undefined. -\rSec3[priqueue.members]{Members} +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. -\indexlibrarymember{push}{priority_queue}% -\begin{itemdecl} -void push(const value_type& x); -\end{itemdecl} +\rSec3[flat.map.defn]{Definition} -\begin{itemdescr} -\pnum -\effects -As if by: \begin{codeblock} -c.push_back(x); -push_heap(c.begin(), c.end(), comp); -\end{codeblock} -\end{itemdescr} +namespace std { + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using key_compare = Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = @\impdefx{type of \tcode{flat_map::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{flat_map::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; -\indexlibrarymember{push}{priority_queue}% -\begin{itemdecl} -void push(value_type&& x); -\end{itemdecl} + class value_compare { + private: + key_compare @\exposid{comp}@; // \expos + constexpr value_compare(key_compare c) : @\exposid{comp}@(c) { } // \expos -\begin{itemdescr} -\pnum -\effects -As if by: -\begin{codeblock} -c.push_back(std::move(x)); -push_heap(c.begin(), c.end(), comp); -\end{codeblock} -\end{itemdescr} + public: + constexpr bool operator()(const_reference x, const_reference y) const { + return @\exposid{comp}@(x.first, y.first); + } + }; -\indexlibrarymember{push_range}{priority_queue}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - void push_range(R&& rg); -\end{itemdecl} + struct containers { + key_container_type keys; + mapped_container_type values; + }; -\begin{itemdescr} -\pnum -\effects -Inserts all elements of \tcode{rg} in \tcode{c} via -\tcode{c.append_range(std::forward(rg))} if that is a valid expression, or -\tcode{ranges::copy(rg, back_inserter(c))} otherwise. -Then restores the heap property as if by -\tcode{make_heap(c.begin(), c.end(), comp)}. + // \ref{flat.map.cons}, constructors + constexpr flat_map() : flat_map(key_compare()) { } -\pnum -\ensures -\tcode{is_heap(c.begin(), c.end(), comp)} is \tcode{true}. -\end{itemdescr} + constexpr explicit flat_map(const key_compare& comp) + : @\exposid{c}@(), @\exposid{compare}@(comp) { } -\indexlibrarymember{emplace}{priority_queue}% -\begin{itemdecl} -template void emplace(Args&&... args); -\end{itemdecl} + constexpr flat_map(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); -\begin{itemdescr} -\pnum -\effects -As if by: -\begin{codeblock} -c.emplace_back(std::forward(args)...); -push_heap(c.begin(), c.end(), comp); -\end{codeblock} -\end{itemdescr} + constexpr flat_map(sorted_unique_t, key_container_type key_cont, + mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + template + constexpr flat_map(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : @\exposid{c}@(), @\exposid{compare}@(comp) { insert(first, last); } -\indexlibrarymember{pop}{priority_queue}% -\begin{itemdecl} -void pop(); -\end{itemdecl} + template + constexpr flat_map(sorted_unique_t s, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : @\exposid{c}@(), @\exposid{compare}@(comp) { insert(s, first, last); } -\begin{itemdescr} -\pnum -\effects -As if by: -\begin{codeblock} -pop_heap(c.begin(), c.end(), comp); -c.pop_back(); -\end{codeblock} -\end{itemdescr} + template<@\exposconcept{container-compatible-range}@ R> + constexpr flat_map(from_range_t, R&& rg) + : flat_map(from_range, std::forward(rg), key_compare()) { } + template<@\exposconcept{container-compatible-range}@ R> + constexpr flat_map(from_range_t, R&& rg, const key_compare& comp) + : flat_map(comp) { insert_range(std::forward(rg)); } -\rSec3[priqueue.special]{Specialized algorithms} + constexpr flat_map(initializer_list il, const key_compare& comp = key_compare()) + : flat_map(il.begin(), il.end(), comp) { } -\indexlibrarymember{swap}{priority_queue}% -\begin{itemdecl} -template - void swap(priority_queue& x, - priority_queue& y) noexcept(noexcept(x.swap(y))); -\end{itemdecl} + constexpr flat_map(sorted_unique_t s, initializer_list il, + const key_compare& comp = key_compare()) + : flat_map(s, il.begin(), il.end(), comp) { } -\begin{itemdescr} -\pnum -\constraints -\tcode{is_swappable_v} is \tcode{true} and -\tcode{is_swappable_v} is \tcode{true}. + // \ref{flat.map.cons.alloc}, constructors with allocators + + template + constexpr explicit flat_map(const Alloc& a); + template + constexpr flat_map(const key_compare& comp, const Alloc& a); + template + constexpr flat_map(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const Alloc& a); + template + constexpr flat_map(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const key_compare& comp, + const Alloc& a); + template + constexpr flat_map(const flat_map&, const Alloc& a); + template + constexpr flat_map(flat_map&&, const Alloc& a); + template + constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_map(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_map(initializer_list il, const Alloc& a); + template + constexpr flat_map(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_map(sorted_unique_t, initializer_list il, const Alloc& a); + template + constexpr flat_map(sorted_unique_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + constexpr flat_map& operator=(initializer_list); -\pnum -\effects -As if by \tcode{x.swap(y)}. -\end{itemdescr} + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; -\rSec2[stack]{Class template \tcode{stack}} + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; -\rSec3[stack.general]{General} + 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; -\pnum -\indexlibraryglobal{stack}% -Any sequence container supporting operations -\tcode{back()}, -\tcode{push_back()} -and -\tcode{pop_back()} -can be used to instantiate -\tcode{stack}. -In particular, -\tcode{vector}\iref{vector}, -\tcode{list}\iref{list} -and -\tcode{deque}\iref{deque} -can be used. + // \ref{flat.map.capacity}, capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; -\rSec3[stack.defn]{Definition} + // \ref{flat.map.access}, element access + constexpr mapped_type& operator[](const key_type& x); + constexpr mapped_type& operator[](key_type&& x); + template constexpr mapped_type& operator[](K&& x); + constexpr mapped_type& at(const key_type& x); + constexpr const mapped_type& at(const key_type& x) const; + template constexpr mapped_type& at(const K& x); + template constexpr const mapped_type& at(const K& x) const; -\begin{codeblock} -namespace std { - template> - class stack { - public: - using value_type = typename Container::value_type; - using reference = typename Container::reference; - using const_reference = typename Container::const_reference; - using size_type = typename Container::size_type; - using container_type = Container; + // \ref{flat.map.modifiers}, modifiers + template constexpr pair emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); - protected: - Container c; + constexpr pair insert(const value_type& x) + { return emplace(x); } + constexpr pair insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template constexpr pair insert(P&& x); + template + constexpr iterator insert(const_iterator position, P&&); + template + constexpr void insert(InputIterator first, InputIterator last); + template + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void insert_range(R&& rg); + + constexpr void insert(initializer_list il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_unique_t s, initializer_list il) + { insert(s, il.begin(), il.end()); } + + constexpr containers extract() &&; + constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); - public: - stack() : stack(Container()) {} - explicit stack(const Container&); - explicit stack(Container&&); - template stack(InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> stack(from_range_t, R&& rg); - template explicit stack(const Alloc&); - template stack(const Container&, const Alloc&); - template stack(Container&&, const Alloc&); - template stack(const stack&, const Alloc&); - template stack(stack&&, const Alloc&); - template - stack(InputIterator first, InputIterator last, const Alloc&); - template<@\exposconcept{container-compatible-range}@ R, class Alloc> - stack(from_range_t, R&& rg, const Alloc&); - - [[nodiscard]] bool empty() const { return c.empty(); } - size_type size() const { return c.size(); } - reference top() { return c.back(); } - const_reference top() const { return c.back(); } - void push(const value_type& x) { c.push_back(x); } - void push(value_type&& x) { c.push_back(std::move(x)); } - template<@\exposconcept{container-compatible-range}@ R> - void push_range(R&& rg); template - decltype(auto) emplace(Args&&... args) - { return c.emplace_back(std::forward(args)...); } - void pop() { c.pop_back(); } - void swap(stack& s) noexcept(is_nothrow_swappable_v) - { using std::swap; swap(c, s.c); } - }; + constexpr pair try_emplace(const key_type& k, Args&&... args); + template + constexpr pair try_emplace(key_type&& k, Args&&... args); + template + constexpr pair try_emplace(K&& k, Args&&... args); + template + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + template + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + template + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + template + constexpr pair insert_or_assign(const key_type& k, M&& obj); + template + constexpr pair insert_or_assign(key_type&& k, M&& obj); + template + constexpr pair insert_or_assign(K&& k, M&& obj); + template + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + template + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + template + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); - template - stack(Container) -> stack; + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); - template - stack(InputIterator, InputIterator) -> stack<@\exposid{iter-value-type}@>; + constexpr void swap(flat_map& y) noexcept; + constexpr void clear() noexcept; - template - stack(from_range_t, R&&) -> stack>; + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; - template - stack(Container, Allocator) -> stack; + constexpr const key_container_type& keys() const noexcept { return @\exposid{c}@.keys; } + constexpr const mapped_container_type& values() const noexcept { return @\exposid{c}@.values; } - template - stack(InputIterator, InputIterator, Allocator) - -> stack<@\exposid{iter-value-type}@, deque<@\exposid{iter-value-type}@, - Allocator>>; + // map operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; + template constexpr pair equal_range(const K& x); + template + constexpr pair equal_range(const K& x) const; - template - stack(from_range_t, R&&, Allocator) - -> stack, deque, Allocator>>; + constexpr friend bool operator==(const flat_map& x, const flat_map& y); - template - struct uses_allocator, Alloc> - : uses_allocator::type { }; -} -\end{codeblock} + constexpr friend @\exposid{synth-three-way-result}@ + operator<=>(const flat_map& x, const flat_map& y); -\rSec3[stack.cons]{Constructors} + constexpr friend void swap(flat_map& x, flat_map& y) noexcept + { x.swap(y); } -\indexlibraryctor{stack}% -\begin{itemdecl} -explicit stack(const Container& cont); -\end{itemdecl} + private: + containers @\exposid{c}@; // \expos + key_compare @\exposid{compare}@; // \expos -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{c} with \tcode{cont}. -\end{itemdescr} + struct @\exposid{key-equiv}@ { // \expos + constexpr @\exposid{key-equiv}@(key_compare c) : comp(c) { } + constexpr bool operator()(const_reference x, const_reference y) const { + return !comp(x.first, y.first) && !comp(y.first, x.first); + } + key_compare comp; + }; + }; -\indexlibraryctor{stack}% -\begin{itemdecl} -explicit stack(Container&& cont); -\end{itemdecl} + template> + flat_map(KeyContainer, MappedContainer, Compare = Compare()) + -> flat_map; -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{c} with \tcode{std::move(cont)}. -\end{itemdescr} + template + flat_map(KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + template + flat_map(KeyContainer, MappedContainer, Compare, Allocator) + -> flat_map; -\indexlibraryctor{stack}% -\begin{itemdecl} -template - stack(InputIterator first, InputIterator last); -\end{itemdecl} + template> + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare = Compare()) + -> flat_map; -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{c} with -\tcode{first} as the first argument and \tcode{last} as the second argument. -\end{itemdescr} + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare, Allocator) + -> flat_map; -\indexlibraryctor{stack}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - stack(from_range_t, R&& rg); -\end{itemdecl} + template>> + flat_map(InputIterator, InputIterator, Compare = Compare()) + -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{c} with \tcode{ranges::to(std::forward(rg))}. -\end{itemdescr} + template>> + flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; -\rSec3[stack.cons.alloc]{Constructors with allocators} + template>, + class Allocator = allocator> + flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare, + vector<@\exposid{range-key-type}@, @\exposid{alloc-rebind}@>>, + vector<@\exposid{range-mapped-type}@, @\exposid{alloc-rebind}@>>>; -\pnum -If \tcode{uses_allocator_v} is \tcode{false} -the constructors in this subclause shall not participate in overload resolution. + template + flat_map(from_range_t, R&&, Allocator) + -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, less<@\exposid{range-key-type}@>, + vector<@\exposid{range-key-type}@, @\exposid{alloc-rebind}@>>, + vector<@\exposid{range-mapped-type}@, @\exposid{alloc-rebind}@>>>; -\indexlibraryctor{stack}% -\begin{itemdecl} -template explicit stack(const Alloc& a); -\end{itemdecl} + template> + flat_map(initializer_list>, Compare = Compare()) + -> flat_map; -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{c} with \tcode{a}. -\end{itemdescr} + template> + flat_map(sorted_unique_t, initializer_list>, Compare = Compare()) + -> flat_map; -\indexlibraryctor{stack}% -\begin{itemdecl} -template stack(const container_type& cont, const Alloc& a); -\end{itemdecl} + template + struct uses_allocator, Allocator> + : bool_constant && + uses_allocator_v> { }; +} +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{cont} as the first argument and \tcode{a} as the -second argument. -\end{itemdescr} +The member type \tcode{containers} has the data members and special members +specified above. +It has no base classes or members other than those specified. -\indexlibraryctor{stack}% +\rSec3[flat.map.cons]{Constructors} + +\indexlibraryctor{flat_map}% \begin{itemdecl} -template stack(container_type&& cont, const Alloc& a); +constexpr flat_map(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \tcode{c} with \tcode{std::move(cont)} as the first argument and \tcode{a} -as the second argument. -\end{itemdescr} - -\indexlibraryctor{stack}% -\begin{itemdecl} -template stack(const stack& s, const Alloc& a); -\end{itemdecl} +Initializes +\tcode{\exposid{c}.keys} with \tcode{std::move(key_cont)}, +\tcode{\exposid{c}.values} with \tcode{std::move(mapped_cont)}, and +\exposid{compare} with \tcode{comp}; +sorts the range \range{begin()}{end()} with respect to \tcode{value_comp()}; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = views::zip(@\exposid{c}@.keys, @\exposid{c}@.values); +auto it = ranges::unique(zv, @\exposid{key-equiv}@(@\exposid{compare}@)).begin(); +auto dist = distance(zv.begin(), it); +@\exposid{c}@.keys.erase(@\exposid{c}@.keys.begin() + dist, @\exposid{c}@.keys.end()); +@\exposid{c}@.values.erase(@\exposid{c}@.values.begin() + dist, @\exposid{c}@.values.end()); +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with \tcode{s.c} as the first argument and \tcode{a} -as the second argument. +\complexity +Linear in $N$ if the container arguments are already sorted +with respect to \tcode{value_comp()} and otherwise $N \log N$, +where $N$ is the value of \tcode{key_cont.size()} before this call. \end{itemdescr} -\indexlibraryctor{stack}% +\indexlibraryctor{flat_map}% \begin{itemdecl} -template stack(stack&& s, const Alloc& a); +constexpr flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \tcode{c} with \tcode{std::move(s.c)} as the first argument and \tcode{a} -as the second argument. -\end{itemdescr} - -\indexlibraryctor{stack}% -\begin{itemdecl} -template - stack(InputIterator first, InputIterator last, const Alloc& alloc); -\end{itemdecl} +Initializes +\tcode{\exposid{c}.keys} with \tcode{std::move(key_cont)}, +\tcode{\exposid{c}.values} with \tcode{std::move(mapped_cont)}, and +\exposid{compare} with \tcode{comp}. -\begin{itemdescr} \pnum -\effects -Initializes \tcode{c} with -\tcode{first} as the first argument, -\tcode{last} as the second argument, and -\tcode{alloc} as the third argument. +\complexity +Constant. \end{itemdescr} -\indexlibraryctor{stack}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R, class Alloc> - stack(from_range_t, R&& rg, const Alloc& a); -\end{itemdecl} +\rSec3[flat.map.cons.alloc]{Constructors with allocators} -\begin{itemdescr} \pnum -\effects -Initializes -\tcode{c} with \tcode{ranges::to(std::forward(rg), a)}. -\end{itemdescr} - -\rSec3[stack.mod]{Modifiers} +The constructors in this subclause shall not participate in overload resolution +unless \tcode{uses_allocator_v} is \tcode{true} +and \tcode{uses_allocator_v} is \tcode{true}. -\indexlibrarymember{push_range}{stack}% +\indexlibraryctor{flat_map}% \begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - void push_range(R&& rg); +template + constexpr flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Alloc& a); +template + constexpr flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{c.append_range(std::forward(rg))} -if that is a valid expression, -otherwise \tcode{ranges::copy(rg, back_inserter(c))}. -\end{itemdescr} - -\rSec3[stack.ops]{Operators} - -\indexlibrarymember{operator==}{stack}% -\begin{itemdecl} -template - bool operator==(const stack& x, const stack& y); -\end{itemdecl} +Equivalent to \tcode{flat_map(key_cont, mapped_cont)} and +\tcode{flat_map(key_cont, mapped_cont, comp)}, respectively, +except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.values} are constructed with +uses-allocator construction\iref{allocator.uses.construction}. -\begin{itemdescr} \pnum -\returns -\tcode{x.c == y.c}. +\complexity +Same as \tcode{flat_map(key_cont, mapped_cont)} and +\tcode{flat_map(key_cont, mapped_cont, comp)}, respectively. \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{stack}}% +\indexlibraryctor{flat_map}% \begin{itemdecl} -template - bool operator!=(const stack& x, const stack& y); +template + constexpr flat_map(sorted_unique_t s, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); +template + constexpr flat_map(sorted_unique_t s, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const key_compare& comp, + const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c != y.c}. +\effects +Equivalent to \tcode{flat_map(s, key_cont, mapped_cont)} and +\tcode{flat_map(s, key_cont, \linebreak{}mapped_cont, comp)}, respectively, +except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. \end{itemdescr} -\indexlibrarymember{operator<}{stack}% +\indexlibraryctor{flat_map}% \begin{itemdecl} -template - bool operator< (const stack& x, const stack& y); +template + constexpr explicit flat_map(const Alloc& a); +template + constexpr flat_map(const key_compare& comp, const Alloc& a); +template + constexpr flat_map(const flat_map&, const Alloc& a); +template + constexpr flat_map(flat_map&&, const Alloc& a); +template + constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a); +template + constexpr flat_map(InputIterator first, InputIterator last, const key_compare& comp, + const Alloc& a); +template + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +template + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); +template + constexpr flat_map(initializer_list il, const Alloc& a); +template + constexpr flat_map(initializer_list il, const key_compare& comp, const Alloc& a); +template + constexpr flat_map(sorted_unique_t, initializer_list il, const Alloc& a); +template + constexpr flat_map(sorted_unique_t, initializer_list il, + const key_compare& comp, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c < y.c}. +\effects +Equivalent to the corresponding non-allocator constructors +except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. \end{itemdescr} -\indexlibrarymember{operator>}{stack}% +\rSec3[flat.map.capacity]{Capacity} + +\indexlibrarymember{size}{flat_map}% \begin{itemdecl} -template - bool operator> (const stack& x, const stack& y); +constexpr size_type size() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.c > y.c}. +\tcode{\exposid{c}.keys.size()}. \end{itemdescr} -\indexlibrarymember{operator<=}{stack}% +\indexlibrarymember{max_size}{flat_map}% \begin{itemdecl} -template - bool operator<=(const stack& x, const stack& y); +constexpr size_type max_size() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.c <= y.c}. +\tcode{min(\exposid{c}.keys.max_size(), \exposid{c}.values.max_size())}. \end{itemdescr} -\indexlibrarymember{operator>=}{stack}% +\rSec3[flat.map.access]{Access} + +\indexlibrarymember{operator[]}{flat_map}% \begin{itemdecl} -template - bool operator>=(const stack& x, const stack& y); +constexpr mapped_type& operator[](const key_type& x); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c >= y.c}. +\effects +Equivalent to: \tcode{return try_emplace(x).first->second;} \end{itemdescr} -\indexlibrarymember{operator<=>}{stack}% +\indexlibrarymember{operator[]}{flat_map}% \begin{itemdecl} -template - compare_three_way_result_t - operator<=>(const stack& x, const stack& y); +constexpr mapped_type& operator[](key_type&& x); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.c <=> y.c}. +\effects +Equivalent to: \tcode{return try_emplace(std::move(x)).first->second;} \end{itemdescr} -\rSec3[stack.special]{Specialized algorithms} - -\indexlibrarymember{swap}{stack}% +\indexlibrarymember{operator[]}{flat_map}% \begin{itemdecl} -template - void swap(stack& x, stack& y) noexcept(noexcept(x.swap(y))); +template constexpr mapped_type& operator[](K&& x); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_swappable_v} is \tcode{true}. +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} is valid and +denotes a type. \pnum \effects -As if by \tcode{x.swap(y)}. +Equivalent to: \tcode{return try_emplace(std::forward(x)).first->second;} \end{itemdescr} -\rSec2[flat.map]{Class template \tcode{flat_map}} - -\rSec3[flat.map.overview]{Overview} - -\pnum -\indexlibraryglobal{flat_map}% -A \tcode{flat_map} is a container adaptor -that provides an associative container interface -that supports unique keys -(i.e., contains at most one of each key value) and -provides for fast retrieval of values of another type \tcode{T} -based on the keys. -\tcode{flat_map} supports iterators -that meet the \oldconcept{InputIterator} requirements and -model the -\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. - -\pnum -A \tcode{flat_map} meets all of the requirements -of a container\iref{container.reqmts} and -of a reversible container\iref{container.rev.reqmts}, -plus the optional container requirements\iref{container.opt.reqmts}. -\tcode{flat_map} meets the requirements of -an associative container\iref{associative.reqmts}, -except that: -\begin{itemize} -\item -it does not meet the requirements related to node handles\iref{container.node}, -\item -it does not meet the requirements related to iterator invalidation, and -\item -the time complexity of the operations that insert or erase a single -element from the map is linear, including the ones that take an insertion -position iterator. -\end{itemize} -\begin{note} -A \tcode{flat_map} does not meet the additional requirements of -an allocator-aware container\iref{container.alloc.reqmts}. -\end{note} - -\pnum -A \tcode{flat_map} also provides most operations -described in \ref{associative.reqmts} for unique keys. -This means that a \tcode{flat_map} supports -the \tcode{a_uniq} operations in \ref{associative.reqmts} -but not the \tcode{a_eq} operations. -For a \tcode{flat_map} -the \tcode{key_type} is \tcode{Key} and -the \tcode{value_type} is \tcode{pair}. +\indexlibrarymember{at}{flat_map}% +\begin{itemdecl} +constexpr mapped_type& at(const key_type& x); +constexpr const mapped_type& at(const key_type& x) const; +\end{itemdecl} +\begin{itemdescr} \pnum -Descriptions are provided here only for operations on \tcode{flat_map} that -are not described in one of those sets of requirements or for operations where -there is additional semantic information. +\returns +A reference to the \tcode{mapped_type} corresponding +to \tcode{x} in \tcode{*this}. \pnum -A \tcode{flat_map} maintains the following invariants: -\begin{itemize} -\item -it contains the same number of keys and values; -\item -the keys are sorted with respect to the comparison object; and -\item -the value at offset \tcode{off} within the value container is -the value associated with the key at offset \tcode{off} -within the key container. -\end{itemize} +\throws +An exception object of type \tcode{out_of_range} if +no such element is present. \pnum -If any member function in \ref{flat.map.defn} exits via an exception -the invariants are restored. -\begin{note} -This can result in the \tcode{flat_map} being emptied. -\end{note} +\complexity +Logarithmic. +\end{itemdescr} -\pnum -Any type \tcode{C} -that meets the sequence container requirements\iref{sequence.reqmts} -can be used to instantiate \tcode{flat_map}, -as long as -\tcode{C::iterator} meets the \oldconcept{RandomAccessIterator} requirements and -invocations of -member functions \tcode{C::size} and \tcode{C::max_size} do not exit via an exception. -In particular, \tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} -can be used. -\begin{note} -\tcode{vector} is not a sequence container. -\end{note} +\indexlibrarymember{at}{flat_map}% +\begin{itemdecl} +template constexpr mapped_type& at(const K& x); +template constexpr const mapped_type& at(const K& x) const; +\end{itemdecl} +\begin{itemdescr} \pnum -The program is ill-formed if -\tcode{Key} is not the same type as \tcode{KeyContainer::value_type} or -\tcode{T} is not the same type as \tcode{MappedContainer::value_type}. +\constraints +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. \pnum -The effect of calling a constructor -that takes -both \tcode{key_container_type} and \tcode{mapped_container_type} arguments with -containers of different sizes is undefined. +\expects +The expression \tcode{find(x)} is well-formed and has well-defined behavior. \pnum -The effect of calling a constructor or member function -that takes a \tcode{sorted_unique_t} argument with -a container, containers, or range -that is not sorted with respect to \tcode{key_comp()}, or -that contains equal elements, -is undefined. - -\rSec3[flat.map.defn]{Definition} - -\begin{codeblock} -namespace std { - template, - class KeyContainer = vector, class MappedContainer = vector> - class flat_map { - public: - // types - using key_type = Key; - using mapped_type = T; - using value_type = pair; - using key_compare = Compare; - using reference = pair; - using const_reference = pair; - using size_type = size_t; - using difference_type = ptrdiff_t; - using iterator = @\impdefx{type of \tcode{flat_map::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{flat_map::const_iterator}}@; // see \ref{container.requirements} - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using key_container_type = KeyContainer; - using mapped_container_type = MappedContainer; - - class value_compare { - private: - key_compare comp; // \expos - value_compare(key_compare c) : comp(c) { } // \expos - - public: - bool operator()(const_reference x, const_reference y) const { - return comp(x.first, y.first); - } - }; - - struct containers { - key_container_type keys; - mapped_container_type values; - }; - - // \ref{flat.map.cons}, construct/copy/destroy - flat_map() : flat_map(key_compare()) { } - - template - flat_map(const flat_map&, const Allocator& a); - template - flat_map(flat_map&&, const Allocator& a); - - flat_map(key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); - template - flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const Allocator& a); - template - flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const key_compare& comp, const Allocator& a); - - flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); - template - flat_map(sorted_unique_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const Allocator& a); - template - flat_map(sorted_unique_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, - const key_compare& comp, const Allocator& a); - - explicit flat_map(const key_compare& comp) - : c(), compare(comp) { } - template - flat_map(const key_compare& comp, const Allocator& a); - template - explicit flat_map(const Allocator& a); - - template - flat_map(InputIterator first, InputIterator last, const key_compare& comp = key_compare()) - : c(), compare(comp) { insert(first, last); } - template - flat_map(InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_map(InputIterator first, InputIterator last, const Allocator& a); - - template<@\exposconcept{container-compatible-range}@ R> - flat_map(from_range_t fr, R&& rg) - : flat_map(fr, std::forward(rg), key_compare()) { } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_map(from_range_t, R&& rg, const Allocator& a); - template<@\exposconcept{container-compatible-range}@ R> - flat_map(from_range_t, R&& rg, const key_compare& comp) - : flat_map(comp) { insert_range(std::forward(rg)); } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_map(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); - - template - flat_map(sorted_unique_t s, InputIterator first, InputIterator last, - const key_compare& comp = key_compare()) - : c(), compare(comp) { insert(s, first, last); } - template - flat_map(sorted_unique_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); - - flat_map(initializer_list il, const key_compare& comp = key_compare()) - : flat_map(il.begin(), il.end(), comp) { } - template - flat_map(initializer_list il, const key_compare& comp, const Allocator& a); - template - flat_map(initializer_list il, const Allocator& a); - - flat_map(sorted_unique_t s, initializer_list il, - const key_compare& comp = key_compare()) - : flat_map(s, il.begin(), il.end(), comp) { } - template - flat_map(sorted_unique_t, initializer_list il, - const key_compare& comp, const Allocator& a); - template - flat_map(sorted_unique_t, initializer_list il, const Allocator& a); - - flat_map& operator=(initializer_list il); - - // 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; - - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() const noexcept; - - // \ref{flat.map.capacity}, capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; - - // \ref{flat.map.access}, element access - mapped_type& operator[](const key_type& x); - mapped_type& operator[](key_type&& x); - template mapped_type& operator[](K&& x); - mapped_type& at(const key_type& x); - const mapped_type& at(const key_type& x) const; - template mapped_type& at(const K& x); - template const mapped_type& at(const K& x) const; - - // \ref{flat.map.modifiers}, modifiers - template pair emplace(Args&&... args); - template - iterator emplace_hint(const_iterator position, Args&&... args); - - pair insert(const value_type& x) - { return emplace(x); } - pair insert(value_type&& x) - { return emplace(std::move(x)); } - iterator insert(const_iterator position, const value_type& x) - { return emplace_hint(position, x); } - iterator insert(const_iterator position, value_type&& x) - { return emplace_hint(position, std::move(x)); } +\returns +A reference to the \tcode{mapped_type} corresponding to +\tcode{x} in \tcode{*this}. - template pair insert(P&& x); - template - iterator insert(const_iterator position, P&&); - template - void insert(InputIterator first, InputIterator last); - template - void insert(sorted_unique_t, InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); +\pnum +\throws +An exception object of type \tcode{out_of_range} +if no such element is present. - void insert(initializer_list il) - { insert(il.begin(), il.end()); } - void insert(sorted_unique_t s, initializer_list il) - { insert(s, il.begin(), il.end()); } +\pnum +\complexity +Logarithmic. +\end{itemdescr} - containers extract() &&; - void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); +\rSec3[flat.map.modifiers]{Modifiers} - template - pair try_emplace(const key_type& k, Args&&... args); - template - pair try_emplace(key_type&& k, Args&&... args); - template - pair try_emplace(K&& k, Args&&... args); - template - iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); - template - iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); - template - iterator try_emplace(const_iterator hint, K&& k, Args&&... args); - template - pair insert_or_assign(const key_type& k, M&& obj); - template - pair insert_or_assign(key_type&& k, M&& obj); - template - pair insert_or_assign(K&& k, M&& obj); - template - iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); - template - iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); - template - iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); +\indexlibrarymember{emplace}{flat_map}% +\begin{itemdecl} +template constexpr pair emplace(Args&&... args); +\end{itemdecl} - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v, Args...>} is \tcode{true}. - void swap(flat_map& y) noexcept; - void clear() noexcept; +\pnum +\effects +Initializes an object \tcode{t} of type \tcode{pair} +with \tcode{std::forward(\linebreak args)...}; +if the map already contains an element +whose key is equivalent to \tcode{t.first}, +\tcode{*this} is unchanged. +Otherwise, equivalent to: +\begin{codeblock} +auto key_it = ranges::upper_bound(@\exposid{c}@.keys, t.first, @\exposid{compare}@); +auto value_it = @\exposid{c}@.values.begin() + distance(@\exposid{c}@.keys.begin(), key_it); +@\exposid{c}@.keys.insert(key_it, std::move(t.first)); +@\exposid{c}@.values.insert(value_it, std::move(t.second)); +\end{codeblock} - // observers - key_compare key_comp() const; - value_compare value_comp() const; +\pnum +\returns +The \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place, and +the iterator component of the pair points to +the element with key equivalent to \tcode{t.first}. +\end{itemdescr} - const key_container_type& keys() const noexcept { return c.keys; } - const mapped_container_type& values() const noexcept { return c.values; } +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template constexpr pair insert(P&& x); +template constexpr iterator insert(const_iterator position, P&& x); +\end{itemdecl} - // map operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v, P>} is \tcode{true}. - size_type count(const key_type& x) const; - template size_type count(const K& x) const; +\pnum +\effects +The first form is equivalent to \tcode{return emplace(std::forward

(x));}. +The second form is equivalent to +\tcode{return emplace_hint(position, std::forward

(x));}. +\end{itemdescr} - bool contains(const key_type& x) const; - template bool contains(const K& x) const; +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template + constexpr void insert(InputIterator first, InputIterator last); +\end{itemdecl} - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; +\begin{itemdescr} +\pnum +\effects +Adds elements to \exposid{c} as if by: +\begin{codeblock} +for (; first != last; ++first) { + value_type value = *first; + @\exposid{c}@.keys.insert(@\exposid{c}@.keys.end(), std::move(value.first)); + @\exposid{c}@.values.insert(@\exposid{c}@.values.end(), std::move(value.second)); +} +\end{codeblock} +Then, sorts the range of newly inserted elements +with respect to \tcode{value_comp()}; +merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = views::zip(@\exposid{c}@.keys, @\exposid{c}@.values); +auto it = ranges::unique(zv, @\exposid{key-equiv}@(@\exposid{compare}@)).begin(); +auto dist = distance(zv.begin(), it); +@\exposid{c}@.keys.erase(@\exposid{c}@.keys.begin() + dist, @\exposid{c}@.keys.end()); +@\exposid{c}@.values.erase(@\exposid{c}@.values.begin() + dist, @\exposid{c}@.values.end()); +\end{codeblock} - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; +\pnum +\complexity +$N$ + $M \log M$, +where $N$ is \tcode{size()} before the operation and +$M$ is \tcode{distance(first, last)}. - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; - template pair equal_range(const K& x); - template pair equal_range(const K& x) const; +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. +\end{itemdescr} - friend bool operator==(const flat_map& x, const flat_map& y); +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); +\end{itemdecl} - friend @\exposid{synth-three-way-result}@ - operator<=>(const flat_map& x, const flat_map& y); +\begin{itemdescr} +\pnum +\effects +Adds elements to \exposid{c} as if by: +\begin{codeblock} +for (; first != last; ++first) { + value_type value = *first; + @\exposid{c}@.keys.insert(@\exposid{c}@.keys.end(), std::move(value.first)); + @\exposid{c}@.values.insert(@\exposid{c}@.values.end(), std::move(value.second)); +} +\end{codeblock} +Then, merges the sorted range of newly added elements and +the sorted range of pre-existing elements into a single sorted range; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = views::zip(@\exposid{c}@.keys, @\exposid{c}@.values); +auto it = ranges::unique(zv, @\exposid{key-equiv}@(@\exposid{compare}@)).begin(); +auto dist = distance(zv.begin(), it); +@\exposid{c}@.keys.erase(@\exposid{c}@.keys.begin() + dist, @\exposid{c}@.keys.end()); +@\exposid{c}@.values.erase(@\exposid{c}@.values.begin() + dist, @\exposid{c}@.values.end()); +\end{codeblock} - friend void swap(flat_map& x, flat_map& y) noexcept - { x.swap(y); } +\pnum +\complexity +Linear in $N$, where $N$ is \tcode{size()} after the operation. - private: - containers c; // \expos - key_compare compare; // \expos +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. +\end{itemdescr} - struct key_equiv { // \expos - key_equiv(key_compare c) : comp(c) { } - bool operator()(const_reference x, const_reference y) const { - return !comp(x.first, y.first) && !comp(y.first, x.first); - } - key_compare comp; - }; - }; +\indexlibrarymember{insert_range}{flat_map}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr void insert_range(R&& rg); +\end{itemdecl} - template> - flat_map(KeyContainer, MappedContainer, Compare = Compare()) - -> flat_map; +\begin{itemdescr} +\pnum +\effects +Adds elements to \exposid{c} as if by: +\begin{codeblock} +for (const auto& e : rg) { + @\exposid{c}@.keys.insert(@\exposid{c}@.keys.end(), e.first); + @\exposid{c}@.values.insert(@\exposid{c}@.values.end(), e.second); +} +\end{codeblock} +Then, sorts the range of newly inserted elements +with respect to \tcode{value_comp()}; +merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range; and +finally erases the duplicate elements as if by: +\begin{codeblock} +auto zv = views::zip(@\exposid{c}@.keys, @\exposid{c}@.values); +auto it = ranges::unique(zv, @\exposid{key-equiv}@(@\exposid{compare}@)).begin(); +auto dist = distance(zv.begin(), it); +@\exposid{c}@.keys.erase(@\exposid{c}@.keys.begin() + dist, @\exposid{c}@.keys.end()); +@\exposid{c}@.values.erase(@\exposid{c}@.values.begin() + dist, @\exposid{c}@.values.end()); +\end{codeblock} - template - flat_map(KeyContainer, MappedContainer, Allocator) - -> flat_map, KeyContainer, MappedContainer>; - template - flat_map(KeyContainer, MappedContainer, Compare, Allocator) - -> flat_map; +\pnum +\complexity +$N$ + $M \log M$, +where $N$ is \tcode{size()} before the operation and +$M$ is \tcode{ranges::distance(rg)}. - template> - flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare = Compare()) - -> flat_map; +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. +\end{itemdescr} - template - flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator) - -> flat_map, KeyContainer, MappedContainer>; - template - flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare, Allocator) - -> flat_map; +\indexlibrarymember{try_emplace}{flat_map}% +\begin{itemdecl} +template + constexpr pair try_emplace(const key_type& k, Args&&... args); +template + constexpr pair try_emplace(key_type&& k, Args&&... args); +template + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); +template + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +\end{itemdecl} - template>> - flat_map(InputIterator, InputIterator, Compare = Compare()) - -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. - template>> - flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) - -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; +\pnum +\effects +If the map already contains an element whose key is equivalent to \tcode{k}, +\tcode{*this} and \tcode{args...} are unchanged. +Otherwise equivalent to: +\begin{codeblock} +auto key_it = ranges::upper_bound(@\exposid{c}@.keys, k, @\exposid{compare}@); +auto value_it = @\exposid{c}@.values.begin() + distance(@\exposid{c}@.keys.begin(), key_it); +@\exposid{c}@.keys.insert(key_it, std::forward(k)); +@\exposid{c}@.values.emplace(value_it, std::forward(args)...); +\end{codeblock} - template>, - class Allocator = allocator> - flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) - -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare, - vector<@\exposid{range-key-type}@, @\exposid{alloc-rebind}@>>, - vector<@\exposid{range-mapped-type}@, @\exposid{alloc-rebind}@>>>; +\pnum +\returns +In the first two overloads, +the \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place. +The returned iterator points to the map element +whose key is equivalent to \tcode{k}. - template - flat_map(from_range_t, R&&, Allocator) - -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, less<@\exposid{range-key-type}@>, - vector<@\exposid{range-key-type}@, @\exposid{alloc-rebind}@>>, - vector<@\exposid{range-mapped-type}@, @\exposid{alloc-rebind}@>>>; +\pnum +\complexity +The same as \tcode{emplace} for the first two overloads, and +the same as \tcode{emplace_hint} for the last two overloads. +\end{itemdescr} - template> - flat_map(initializer_list>, Compare = Compare()) - -> flat_map; +\indexlibrarymember{try_emplace}{flat_map}% +\begin{itemdecl} +template + constexpr pair try_emplace(K&& k, Args&&... args); +template + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. +\item +\tcode{is_constructible_v} is \tcode{true}. +\item +\tcode{is_constructible_v} is \tcode{true}. +\item +For the first overload, +\tcode{is_convertible_v} and +\tcode{is_convertible_v} are both \tcode{false}. +\end{itemize} - template> - flat_map(sorted_unique_t, initializer_list>, Compare = Compare()) - -> flat_map; +\pnum +\expects +The conversion from \tcode{k} into \tcode{key_type} constructs +an object \tcode{u}, +for which \tcode{find(k) == find(u)} is \tcode{true}. - template - struct uses_allocator, Allocator> - : bool_constant && - uses_allocator_v> { }; -} +\pnum +\effects +If the map already contains an element whose key is equivalent to \tcode{k}, +\tcode{*this} and \tcode{args...} are unchanged. +Otherwise equivalent to: +\begin{codeblock} +auto key_it = ranges::upper_bound(@\exposid{c}@.keys, k, @\exposid{compare}@); +auto value_it = @\exposid{c}@.values.begin() + distance(@\exposid{c}@.keys.begin(), key_it); +@\exposid{c}@.keys.emplace(key_it, std::forward(k)); +@\exposid{c}@.values.emplace(value_it, std::forward(args)...); \end{codeblock} \pnum -The member type \tcode{containers} has the data members and special members -specified above. -It has no base classes or members other than those specified. +\returns +In the first overload, +the \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place. +The returned iterator points to the map element +whose key is equivalent to \tcode{k}. -\rSec3[flat.map.cons]{Constructors} +\pnum +\complexity +The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. +\end{itemdescr} -\indexlibraryctor{flat_map}% +\indexlibrarymember{insert_or_assign}{flat_map}% \begin{itemdecl} -flat_map(key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); +template + constexpr pair insert_or_assign(const key_type& k, M&& obj); +template + constexpr pair insert_or_assign(key_type&& k, M&& obj); +template + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); +template + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{is_assignable_v} is \tcode{true} and +\tcode{is_constructible_v} is \tcode{true}. + \pnum \effects -Initializes -\tcode{c.keys} with \tcode{std::move(key_cont)}, -\tcode{c.values} with \tcode{std::move(mapped_cont)}, and -\tcode{compare} with \tcode{comp}; -sorts the range \range{begin()}{end()} with respect to \tcode{value_comp()}; and -finally erases the duplicate elements as if by: +If the map already contains an element \tcode{e} +whose key is equivalent to \tcode{k}, +assigns \tcode{std::forward<\linebreak M>(obj)} to \tcode{e.second}. +Otherwise, equivalent to \begin{codeblock} -auto zv = views::zip(c.keys, c.values); -auto it = ranges::unique(zv, key_equiv(compare)).begin(); -auto dist = distance(zv.begin(), it); -c.keys.erase(c.keys.begin() + dist, c.keys.end()); -c.values.erase(c.values.begin() + dist, c.values.end()); +try_emplace(std::forward(k), std::forward(obj)) +\end{codeblock} +for the first two overloads or +\begin{codeblock} +try_emplace(hint, std::forward(k), std::forward(obj)) \end{codeblock} +for the last two overloads. + +\pnum +\returns +In the first two overloads, the \tcode{bool} component of the returned pair +is \tcode{true} if and only if the insertion took place. The returned +iterator points to the map element whose key is equivalent to \tcode{k}. \pnum \complexity -Linear in $N$ if the container arguments are already sorted -with respect to \tcode{value_comp()} and otherwise $N \log N$, -where $N$ is the value of \tcode{key_cont.size()} before this call. +The same as \tcode{emplace} for the first two overloads and +the same as \tcode{emplace_hint} for the last two overloads. \end{itemdescr} -\indexlibraryctor{flat_map}% +\indexlibrarymember{insert_or_assign}{flat_map}% \begin{itemdecl} -template - flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const Allocator& a); -template - flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const key_compare& comp, const Allocator& a); +template + constexpr pair insert_or_assign(K&& k, M&& obj); +template + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{uses_allocator_v} is \tcode{true} and -\tcode{uses_allocator_v} is \tcode{true}. +\begin{itemize} +\item +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. +\item +\tcode{is_constructible_v} is \tcode{true}. +\item +\tcode{is_assignable_v} is \tcode{true}. +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\expects +The conversion from \tcode{k} into \tcode{key_type} constructs +an object \tcode{u}, for which \tcode{find(k) == find(u)} is \tcode{true}. \pnum \effects -Equivalent to \tcode{flat_map(key_cont, mapped_cont)} and -\tcode{flat_map(key_cont, mapped_cont, comp)}, respectively, -except that \tcode{c.keys} and \tcode{c.values} are constructed with -uses-allocator construction\iref{allocator.uses.construction}. +If the map already contains an element \tcode{e} +whose key is equivalent to \tcode{k}, +assigns \tcode{std::forward<\linebreak M>(obj)} to \tcode{e.second}. +Otherwise, equivalent to +\begin{codeblock} +try_emplace(std::forward(k), std::forward(obj)) +\end{codeblock} +for the first overload or +\begin{codeblock} +try_emplace(hint, std::forward(k), std::forward(obj)) +\end{codeblock} +for the second overload. + +\pnum +\returns +In the first overload, +the \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place. +The returned iterator points to the map element +whose key is equivalent to \tcode{k}. \pnum \complexity -Same as \tcode{flat_map(key_cont, mapped_cont)} and -\tcode{flat_map(key_cont, mapped_cont, comp)}, respectively. +The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. \end{itemdescr} -\indexlibraryctor{flat_map}% +\indexlibrarymember{swap}{flat_map}% \begin{itemdecl} -flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); +constexpr void swap(flat_map& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes -\tcode{c.keys} with \tcode{std::move(key_cont)}, -\tcode{c.values} with \tcode{std::move(mapped_cont)}, and -\tcode{compare} with \tcode{comp}. +Equivalent to: +\begin{codeblock} +ranges::swap(@\exposid{compare}@, y.@\exposid{compare}@); +ranges::swap(@\exposid{c}@.keys, y.@\exposid{c}@.keys); +ranges::swap(@\exposid{c}@.values, y.@\exposid{c}@.values); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{extract}{flat_map}% +\begin{itemdecl} +constexpr containers extract() &&; +\end{itemdecl} +\begin{itemdescr} \pnum -\complexity -Constant. +\ensures +\tcode{*this} is emptied, even if the function exits via an exception. + +\pnum +\returns +\tcode{std::move(\exposid{c})}. \end{itemdescr} -\indexlibraryctor{flat_map}% +\indexlibrarymember{replace}{flat_map}% \begin{itemdecl} -template - flat_map(sorted_unique_t s, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const Allocator& a); -template - flat_map(sorted_unique_t s, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const key_compare& comp, - const Allocator& a); +constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true} and -\tcode{uses_allocator_v} is \tcode{true}. +\expects +\tcode{key_cont.size() == mapped_cont.size()} is \tcode{true}, +the elements of \tcode{key_cont} are sorted with respect to \exposid{compare}, and +\tcode{key_cont} contains no equal elements. \pnum \effects -Equivalent to \tcode{flat_map(s, key_cont, mapped_cont)} and -\tcode{flat_map(s, key_cont, \linebreak{}mapped_cont, comp)}, respectively, -except that \tcode{c.keys} and \tcode{c.values} are constructed -with uses-allocator construction\iref{allocator.uses.construction}. - -\pnum -\complexity -Linear. +Equivalent to: +\begin{codeblock} +@\exposid{c}@.keys = std::move(key_cont); +@\exposid{c}@.values = std::move(mapped_cont); +\end{codeblock} \end{itemdescr} -\indexlibraryctor{flat_map}% +\rSec3[flat.map.erasure]{Erasure} + +\indexlibrarymember{erase_if}{flat_map}% \begin{itemdecl} -template - flat_map(const flat_map&, const Allocator& a); -template - flat_map(flat_map&&, const Allocator& a); -template - flat_map(const key_compare& comp, const Allocator& a); -template - explicit flat_map(const Allocator& a); -template - flat_map(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); -template - flat_map(InputIterator first, InputIterator last, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_map(from_range_t, R&& rg, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_map(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); -template - flat_map(sorted_unique_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); -template - flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); -template - flat_map(initializer_list il, const key_compare& comp, const Allocator& a); -template - flat_map(initializer_list il, const Allocator& a); -template - flat_map(sorted_unique_t, initializer_list il, - const key_compare& comp, const Allocator& a); -template - flat_map(sorted_unique_t, initializer_list il, const Allocator& a); +template + constexpr typename flat_map::size_type + erase_if(flat_map& c, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true} and -\tcode{uses_allocator_v} is \tcode{true}. +\expects +\tcode{Key} and \tcode{T} meet the \oldconcept{MoveAssignable} requirements. \pnum \effects -Equivalent to the corresponding non-allocator constructors -except that \tcode{c.keys} and \tcode{c.values} are constructed -with uses-allocator construction\iref{allocator.uses.construction}. +Let $E$ be \tcode{bool(pred(pair(e)))}. +Erases all elements \tcode{e} in \tcode{c} for which $E$ holds. + +\pnum +\returns +The number of elements erased. + +\pnum +\complexity +Exactly \tcode{c.size()} applications of the predicate. + +\pnum +\remarks +Stable\iref{algorithm.stable}. +If an invocation of \tcode{erase_if} exits via an exception, +\tcode{c} is in a valid but unspecified state\iref{defns.valid}. +\begin{note} +\tcode{c} still meets its invariants, +but can be empty. +\end{note} \end{itemdescr} -\rSec3[flat.map.capacity]{Capacity} +\rSec2[flat.multimap]{Class template \tcode{flat_multimap}} -\indexlibrarymember{size}{flat_map}% -\begin{itemdecl} -size_type size() const noexcept; -\end{itemdecl} +\rSec3[flat.multimap.overview]{Overview} + +\pnum +\indexlibraryglobal{flat_multimap}% +A \tcode{flat_multimap} is a container adaptor +that provides an associative container interface +that supports equivalent keys +(i.e., possibly containing multiple copies of the same key value) and +provides for fast retrieval of values of another type \tcode{T} +based on the keys. +\tcode{flat_multimap} supports iterators that meet +the \oldconcept{InputIterator} requirements and +model the +\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. + +\pnum +A \tcode{flat_multimap} meets all of the requirements +for a container\iref{container.reqmts} and +for a reversible container\iref{container.rev.reqmts}, +plus the optional container requirements\iref{container.opt.reqmts}. +\tcode{flat_multimap} meets the requirements of +an associative container\iref{associative.reqmts}, except that: +\begin{itemize} +\item +it does not meet the requirements related to node handles\iref{container.node}, +\item +it does not meet the requirements related to iterator invalidation, and +\item +the time complexity of the operations +that insert or erase a single element from the map is linear, +including the ones that take an insertion position iterator. +\end{itemize} +\begin{note} +A \tcode{flat_multimap} does not meet the additional requirements of an +allocator-aware container\iref{container.alloc.reqmts}. +\end{note} + +\pnum +A \tcode{flat_multimap} also provides most operations described +in \ref{associative.reqmts} for equal keys. +This means that a \tcode{flat_multimap} supports +the \tcode{a_eq} operations in \ref{associative.reqmts} +but not the \tcode{a_uniq} operations. +For a \tcode{flat_multimap} +the \tcode{key_type} is \tcode{Key} and +the \tcode{value_type} is \tcode{pair}. + +\pnum +Except as otherwise noted, +operations on \tcode{flat_multimap} are equivalent to those of \tcode{flat_map}, +except that \tcode{flat_multimap} operations +do not remove or replace elements with equal keys. +\begin{example} +\tcode{flat_multimap} constructors and emplace do not erase +non-unique elements after sorting them. +\end{example} + +\pnum +A \tcode{flat_multimap} maintains the following invariants: +\begin{itemize} +\item +it contains the same number of keys and values; +\item +the keys are sorted with respect to the comparison object; and +\item +the value at offset \tcode{off} within the value container is the value +associated with the key at offset \tcode{off} within the key container. +\end{itemize} -\begin{itemdescr} \pnum -\returns -\tcode{c.keys.size()}. -\end{itemdescr} - -\indexlibrarymember{max_size}{flat_map}% -\begin{itemdecl} -size_type max_size() const noexcept; -\end{itemdecl} +If any member function in \ref{flat.multimap.defn} exits via an exception, +the invariants are restored. +\begin{note} +This can result in the \tcode{flat_multimap} being emptied. +\end{note} -\begin{itemdescr} \pnum -\returns -\tcode{min(c.keys.max_size(), c.values.max_size())}. -\end{itemdescr} - -\rSec3[flat.map.access]{Access} - -\indexlibrarymember{operator[]}{flat_map}% -\begin{itemdecl} -mapped_type& operator[](const key_type& x); -\end{itemdecl} +Any type \tcode{C} +that meets the sequence container requirements\iref{sequence.reqmts} +can be used to instantiate \tcode{flat_multimap}, +as long as +\tcode{C::iterator} meets the \oldconcept{RandomAccessIterator} requirements and +invocations of +member functions \tcode{C::size} and \tcode{C::max_size} do not exit via an exception. +In particular, +\tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} can be used. +\begin{note} +\tcode{vector} is not a sequence container. +\end{note} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return try_emplace(x).first->second;} -\end{itemdescr} - -\indexlibrarymember{operator[]}{flat_map}% -\begin{itemdecl} -mapped_type& operator[](key_type&& x); -\end{itemdecl} +The program is ill-formed if +\tcode{Key} is not the same type as \tcode{KeyContainer::value_type} or +\tcode{T} is not the same type as \tcode{MappedContainer::value_type}. -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return try_emplace(std::move(x)).first->second;} -\end{itemdescr} - -\indexlibrarymember{operator[]}{flat_map}% -\begin{itemdecl} -template mapped_type& operator[](K&& x); -\end{itemdecl} +The effect of calling a constructor +that takes both \tcode{key_container_type} and +\tcode{mapped_container_type} arguments +with containers of different sizes is undefined. -\begin{itemdescr} \pnum -\constraints -The \grammarterm{qualified-id} \tcode{Compare::is_transparent} is valid and -denotes a type. +The effect of calling a constructor or member function +that takes a \tcode{sorted_equivalent_t} argument +with a container, containers, or range +that are not sorted with respect to \tcode{key_comp()} is undefined. \pnum -\effects -Equivalent to: \tcode{return try_emplace(std::forward(x)).first->second;} -\end{itemdescr} +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. -\indexlibrarymember{at}{flat_map}% -\begin{itemdecl} -mapped_type& at(const key_type& x); -const mapped_type& at(const key_type& x) const; -\end{itemdecl} +\rSec3[flat.multimap.defn]{Definition} -\begin{itemdescr} -\pnum -\returns -A reference to the \tcode{mapped_type} corresponding -to \tcode{x} in \tcode{*this}. +\begin{codeblock} +namespace std { + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_multimap { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair; + using key_compare = Compare; + using reference = pair; + using const_reference = pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = @\impdefx{type of \tcode{flat_multimap::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{flat_multimap::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; -\pnum -\throws -An exception object of type \tcode{out_of_range} if -no such element is present. + class value_compare { + private: + key_compare @\exposid{comp}@; // \expos + constexpr value_compare(key_compare c) : @\exposid{comp}@(c) { } // \expos -\pnum -\complexity -Logarithmic. -\end{itemdescr} + public: + constexpr bool operator()(const_reference x, const_reference y) const { + return @\exposid{comp}@(x.first, y.first); + } + }; -\indexlibrarymember{at}{flat_map}% -\begin{itemdecl} -template mapped_type& at(const K& x); -template const mapped_type& at(const K& x) const; -\end{itemdecl} + struct containers { + key_container_type keys; + mapped_container_type values; + }; -\begin{itemdescr} -\pnum -\constraints -The \grammarterm{qualified-id} \tcode{Compare::is_transparent} -is valid and denotes a type. + // \ref{flat.multimap.cons}, constructors + constexpr flat_multimap() : flat_multimap(key_compare()) { } -\pnum -\expects -The expression \tcode{find(x)} is well-formed and has well-defined behavior. + constexpr explicit flat_multimap(const key_compare& comp) + : @\exposid{c}@(), @\exposid{compare}@(comp) { } -\pnum -\returns -A reference to the \tcode{mapped_type} corresponding to -\tcode{x} in \tcode{*this}. + constexpr flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); -\pnum -\throws -An exception object of type \tcode{out_of_range} -if no such element is present. + constexpr flat_multimap(sorted_equivalent_t, + key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); -\pnum -\complexity -Logarithmic. -\end{itemdescr} + template + constexpr flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : @\exposid{c}@(), @\exposid{compare}@(comp) + { insert(first, last); } -\rSec3[flat.map.modifiers]{Modifiers} + template + constexpr flat_multimap(sorted_equivalent_t s, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : @\exposid{c}@(), @\exposid{compare}@(comp) { insert(s, first, last); } -\indexlibrarymember{emplace}{flat_map}% -\begin{itemdecl} -template pair emplace(Args&&... args); -\end{itemdecl} + template<@\exposconcept{container-compatible-range}@ R> + constexpr flat_multimap(from_range_t, R&& rg) + : flat_multimap(from_range, std::forward(rg), key_compare()) { } + template<@\exposconcept{container-compatible-range}@ R> + constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp) + : flat_multimap(comp) { insert_range(std::forward(rg)); } -\begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v, Args...>} is \tcode{true}. + constexpr flat_multimap(initializer_list il, + const key_compare& comp = key_compare()) + : flat_multimap(il.begin(), il.end(), comp) { } -\pnum -\effects -Initializes an object \tcode{t} of type \tcode{pair} -with \tcode{std::forward(\linebreak args)...}; -if the map already contains an element -whose key is equivalent to \tcode{t.first}, -\tcode{*this} is unchanged. -Otherwise, equivalent to: -\begin{codeblock} -auto key_it = ranges::upper_bound(c.keys, t.first, compare); -auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); -c.keys.insert(key_it, std::move(t.first)); -c.values.insert(value_it, std::move(t.second)); -\end{codeblock} + constexpr flat_multimap(sorted_equivalent_t s, initializer_list il, + const key_compare& comp = key_compare()) + : flat_multimap(s, il.begin(), il.end(), comp) { } -\pnum -\returns -The \tcode{bool} component of the returned pair is \tcode{true} -if and only if the insertion took place, and -the iterator component of the pair points to -the element with key equivalent to \tcode{t.first}. -\end{itemdescr} + // \ref{flat.multimap.cons.alloc}, constructors with allocators + + template + constexpr explicit flat_multimap(const Alloc& a); + template + constexpr flat_multimap(const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(const flat_multimap&, const Alloc& a); + template + constexpr flat_multimap(flat_multimap&&, const Alloc& a); + template + constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_multimap(initializer_list il, const Alloc& a); + template + constexpr flat_multimap(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, initializer_list il, + const Alloc& a); + template + constexpr flat_multimap(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + flat_multimap& operator=(initializer_list); -\indexlibrarymember{insert}{flat_map}% -\begin{itemdecl} -template pair insert(P&& x); -template iterator insert(const_iterator position, P&& x); -\end{itemdecl} + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; -\begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v, P>} is \tcode{true}. + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; -\pnum -\effects -The first form is equivalent to \tcode{return emplace(std::forward

(x));}. -The second form is equivalent to -\tcode{return emplace_hint(position, std::forward

(x));}. -\end{itemdescr} + 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; -\indexlibrarymember{insert}{flat_map}% -\begin{itemdecl} -template - void insert(InputIterator first, InputIterator last); -\end{itemdecl} + // capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; -\begin{itemdescr} -\pnum -\effects -Adds elements to \tcode{c} as if by: -\begin{codeblock} -for (; first != last; ++first) { - value_type value = *first; - c.keys.insert(c.keys.end(), std::move(value.first)); - c.values.insert(c.values.end(), std::move(value.second)); -} -\end{codeblock} -Then, sorts the range of newly inserted elements -with respect to \tcode{value_comp()}; -merges the resulting sorted range and -the sorted range of pre-existing elements into a single sorted range; and -finally erases the duplicate elements as if by: -\begin{codeblock} -auto zv = views::zip(c.keys, c.values); -auto it = ranges::unique(zv, key_equiv(compare)).begin(); -auto dist = distance(zv.begin(), it); -c.keys.erase(c.keys.begin() + dist, c.keys.end()); -c.values.erase(c.values.begin() + dist, c.values.end()); -\end{codeblock} + // modifiers + template constexpr iterator emplace(Args&&... args); + template + constexpr iterator emplace_hint(const_iterator position, Args&&... args); -\pnum -\complexity -$N$ + $M \log M$, -where $N$ is \tcode{size()} before the operation and -$M$ is \tcode{distance(first, last)}. + constexpr iterator insert(const value_type& x) + { return emplace(x); } + constexpr iterator insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } -\pnum -\remarks -Since this operation performs an in-place merge, it may allocate memory. -\end{itemdescr} + template constexpr iterator insert(P&& x); + template + constexpr iterator insert(const_iterator position, P&&); + template + constexpr void insert(InputIterator first, InputIterator last); + template + constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr void insert_range(R&& rg); -\indexlibrarymember{insert}{flat_map}% -\begin{itemdecl} -template - void insert(sorted_unique_t, InputIterator first, InputIterator last); -\end{itemdecl} + constexpr void insert(initializer_list il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_equivalent_t s, initializer_list il) + { insert(s, il.begin(), il.end()); } -\begin{itemdescr} -\pnum -\effects -Adds elements to \tcode{c} as if by: -\begin{codeblock} -for (; first != last; ++first) { - value_type value = *first; - c.keys.insert(c.keys.end(), std::move(value.first)); - c.values.insert(c.values.end(), std::move(value.second)); -} -\end{codeblock} -Then, merges the sorted range of newly added elements and -the sorted range of pre-existing elements into a single sorted range; and -finally erases the duplicate elements as if by: -\begin{codeblock} -auto zv = views::zip(c.keys, c.values); -auto it = ranges::unique(zv, key_equiv(compare)).begin(); -auto dist = distance(zv.begin(), it); -c.keys.erase(c.keys.begin() + dist, c.keys.end()); -c.values.erase(c.values.begin() + dist, c.values.end()); -\end{codeblock} + constexpr containers extract() &&; + constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); -\pnum -\complexity -Linear in $N$, where $N$ is \tcode{size()} after the operation. + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); -\pnum -\remarks -Since this operation performs an in-place merge, it may allocate memory. -\end{itemdescr} + constexpr void swap(flat_multimap&) noexcept; + constexpr void clear() noexcept; -\indexlibrarymember{insert_range}{flat_map}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); -\end{itemdecl} + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; -\begin{itemdescr} -\pnum -\effects -Adds elements to \tcode{c} as if by: -\begin{codeblock} -for (const auto& e : rg) { - c.keys.insert(c.keys.end(), e.first); - c.values.insert(c.values.end(), e.second); -} -\end{codeblock} -Then, sorts the range of newly inserted elements -with respect to \tcode{value_comp()}; -merges the resulting sorted range and -the sorted range of pre-existing elements into a single sorted range; and -finally erases the duplicate elements as if by: -\begin{codeblock} -auto zv = views::zip(c.keys, c.values); -auto it = ranges::unique(zv, key_equiv(compare)).begin(); -auto dist = distance(zv.begin(), it); -c.keys.erase(c.keys.begin() + dist, c.keys.end()); -c.values.erase(c.values.begin() + dist, c.values.end()); -\end{codeblock} + constexpr const key_container_type& keys() const noexcept { return @\exposid{c}@.keys; } + constexpr const mapped_container_type& values() const noexcept { return @\exposid{c}@.values; } -\pnum -\complexity -$N$ + $M \log M$, -where $N$ is \tcode{size()} before the operation and -$M$ is \tcode{ranges::distance(rg)}. + // map operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; -\pnum -\remarks -Since this operation performs an in-place merge, it may allocate memory. -\end{itemdescr} + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; -\indexlibrarymember{try_emplace}{flat_map}% -\begin{itemdecl} -template - pair try_emplace(const key_type& k, Args&&... args); -template - pair try_emplace(key_type&& k, Args&&... args); -template - iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); -template - iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); -\end{itemdecl} + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; -\begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v} is \tcode{true}. + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; -\pnum -\effects -If the map already contains an element whose key is equivalent to \tcode{k}, -\tcode{*this} and \tcode{args...} are unchanged. -Otherwise equivalent to: -\begin{codeblock} -auto key_it = ranges::upper_bound(c.keys, k, compare); -auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); -c.keys.insert(key_it, std::forward(k)); -c.values.emplace(value_it, std::forward(args)...); -\end{codeblock} + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; -\pnum -\returns -In the first two overloads, -the \tcode{bool} component of the returned pair is \tcode{true} -if and only if the insertion took place. -The returned iterator points to the map element -whose key is equivalent to \tcode{k}. + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; + template + constexpr pair equal_range(const K& x); + template + constexpr pair equal_range(const K& x) const; -\pnum -\complexity -The same as \tcode{emplace} for the first two overloads, and -the same as \tcode{emplace_hint} for the last two overloads. -\end{itemdescr} + constexpr friend bool operator==(const flat_multimap& x, const flat_multimap& y); -\indexlibrarymember{try_emplace}{flat_map}% -\begin{itemdecl} -template - pair try_emplace(K&& k, Args&&... args); -template - iterator try_emplace(const_iterator hint, K&& k, Args&&... args); -\end{itemdecl} + constexpr friend @\exposid{synth-three-way-result}@ + operator<=>(const flat_multimap& x, const flat_multimap& y); -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item -The \grammarterm{qualified-id} \tcode{Compare::is_transparent} -is valid and denotes a type. -\item -\tcode{is_constructible_v} is \tcode{true}. -\item -\tcode{is_constructible_v} is \tcode{true}. -\item -For the first overload, -\tcode{is_convertible_v} and -\tcode{is_convertible_v} are both \tcode{false}. -\end{itemize} + constexpr friend void swap(flat_multimap& x, flat_multimap& y) noexcept + { x.swap(y); } -\pnum -\expects -The conversion from \tcode{k} into \tcode{key_type} constructs -an object \tcode{u}, -for which \tcode{find(k) == find(u)} is \tcode{true}. + private: + containers @\exposid{c}@; // \expos + key_compare @\exposid{compare}@; // \expos + }; -\pnum -\effects -If the map already contains an element whose key is equivalent to \tcode{k}, -\tcode{*this} and \tcode{args...} are unchanged. -Otherwise equivalent to: -\begin{codeblock} -auto key_it = ranges::upper_bound(c.keys, k, compare); -auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); -c.keys.emplace(key_it, std::forward(k)); -c.values.emplace(value_it, std::forward(args)...); -\end{codeblock} + template> + flat_multimap(KeyContainer, MappedContainer, Compare = Compare()) + -> flat_multimap; -\pnum -\returns -In the first overload, -the \tcode{bool} component of the returned pair is \tcode{true} -if and only if the insertion took place. -The returned iterator points to the map element -whose key is equivalent to \tcode{k}. + template + flat_multimap(KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + template + flat_multimap(KeyContainer, MappedContainer, Compare, Allocator) + -> flat_multimap; -\pnum -\complexity -The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. -\end{itemdescr} + template> + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare()) + -> flat_multimap; -\indexlibrarymember{insert_or_assign}{flat_map}% -\begin{itemdecl} -template - pair insert_or_assign(const key_type& k, M&& obj); -template - pair insert_or_assign(key_type&& k, M&& obj); -template - iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); -template - iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); -\end{itemdecl} + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator) + -> flat_multimap; -\begin{itemdescr} -\pnum -\constraints -\tcode{is_assignable_v} is \tcode{true} and -\tcode{is_constructible_v} is \tcode{true}. + template>> + flat_multimap(InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; -\pnum -\effects -If the map already contains an element \tcode{e} -whose key is equivalent to \tcode{k}, -assigns \tcode{std::forward<\linebreak M>(obj)} to \tcode{e.second}. -Otherwise, equivalent to -\begin{codeblock} -try_emplace(std::forward(k), std::forward(obj)) -\end{codeblock} -for the first two overloads or -\begin{codeblock} -try_emplace(hint, std::forward(k), std::forward(obj)) -\end{codeblock} -for the last two overloads. + template>> + flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; -\pnum -\returns -In the first two overloads, the \tcode{bool} component of the returned pair -is \tcode{true} if and only if the insertion took place. The returned -iterator points to the map element whose key is equivalent to \tcode{k}. + template>, + class Allocator = allocator> + flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare, + vector<@\exposid{range-key-type}@, + @\exposid{alloc-rebind}@>>, + vector<@\exposid{range-mapped-type}@, + @\exposid{alloc-rebind}@>>>; -\pnum -\complexity -The same as \tcode{emplace} for the first two overloads and -the same as \tcode{emplace_hint} for the last two overloads. -\end{itemdescr} + template + flat_multimap(from_range_t, R&&, Allocator) + -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, less<@\exposid{range-key-type}@>, + vector<@\exposid{range-key-type}@, + @\exposid{alloc-rebind}@>>, + vector<@\exposid{range-mapped-type}@, + @\exposid{alloc-rebind}@>>>; -\indexlibrarymember{insert_or_assign}{flat_map}% -\begin{itemdecl} -template - pair insert_or_assign(K&& k, M&& obj); -template - iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); -\end{itemdecl} + template> + flat_multimap(initializer_list>, Compare = Compare()) + -> flat_multimap; + + template> + flat_multimap(sorted_equivalent_t, initializer_list>, Compare = Compare()) + -> flat_multimap; + + template + struct uses_allocator, + Allocator> + : bool_constant && + uses_allocator_v> { }; +} +\end{codeblock} -\begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -The \grammarterm{qualified-id} \tcode{Compare::is_transparent} -is valid and denotes a type. -\item -\tcode{is_constructible_v} is \tcode{true}. -\item -\tcode{is_assignable_v} is \tcode{true}. -\item -\tcode{is_constructible_v} is \tcode{true}. -\end{itemize} +The member type \tcode{containers} has the data members and special members +specified above. It has no base classes or members other than those +specified. + +\rSec3[flat.multimap.cons]{Constructors} -\pnum -\expects -The conversion from \tcode{k} into \tcode{key_type} constructs -an object \tcode{u}, for which \tcode{find(k) == find(u)} is \tcode{true}. +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +constexpr flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); +\end{itemdecl} +\begin{itemdescr} \pnum \effects -If the map already contains an element \tcode{e} -whose key is equivalent to \tcode{k}, -assigns \tcode{std::forward<\linebreak M>(obj)} to \tcode{e.second}. -Otherwise, equivalent to -\begin{codeblock} -try_emplace(std::forward(k), std::forward(obj)) -\end{codeblock} -for the first overload or -\begin{codeblock} -try_emplace(hint, std::forward(k), std::forward(obj)) -\end{codeblock} -for the second overload. - -\pnum -\returns -In the first overload, -the \tcode{bool} component of the returned pair is \tcode{true} -if and only if the insertion took place. -The returned iterator points to the map element -whose key is equivalent to \tcode{k}. +Initializes +\tcode{\exposid{c}.keys} with \tcode{std::move(key_cont)}, +\tcode{\exposid{c}.values} with \tcode{std::move(mapped_cont)}, and +\exposid{compare} with \tcode{comp}; +sorts the range \range{begin()}{end()} with respect to \tcode{value_comp()}. \pnum \complexity -The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. +Linear in $N$ if the container arguments are already sorted +with respect to \tcode{value_comp()} and otherwise $N \log N$, +where $N$ is the value of \tcode{key_cont.size()} before this call. \end{itemdescr} -\indexlibrarymember{swap}{flat_map}% +\indexlibraryctor{flat_multimap}% \begin{itemdecl} -void swap(flat_map& y) noexcept; +constexpr flat_multimap(sorted_equivalent_t, key_container_type key_cont, + mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -ranges::swap(compare, y.compare); -ranges::swap(c.keys, y.c.keys); -ranges::swap(c.values, y.c.values); -\end{codeblock} +Initializes +\tcode{\exposid{c}.keys} with \tcode{std::move(key_cont)}, +\tcode{\exposid{c}.values} with \tcode{std::move(mapped_cont)}, and +\exposid{compare} with \tcode{comp}. + +\pnum +\complexity +Constant. \end{itemdescr} -\indexlibrarymember{extract}{flat_map}% +\rSec3[flat.multimap.cons.alloc]{Constructors with allocators} + +\pnum +The constructors in this subclause shall not participate in overload resolution +unless \tcode{uses_allocator_v} is \tcode{true} +and \tcode{uses_allocator_v} is \tcode{true}. + +\indexlibraryctor{flat_multimap}% \begin{itemdecl} -containers extract() &&; +template + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); +template + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum -\ensures -\tcode{*this} is emptied, even if the function exits via an exception. +\effects +Equivalent to \tcode{flat_multimap(key_cont, mapped_cont)} and +\tcode{flat_multimap(key_cont, \linebreak{}mapped_cont, comp)}, respectively, +except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. \pnum -\returns -\tcode{std::move(c)}. +\complexity +Same as \tcode{flat_multimap(key_cont, mapped_cont)} and +\tcode{flat_multimap(key_cont, \linebreak{}mapped_cont, comp)}, respectively. \end{itemdescr} -\indexlibrarymember{replace}{flat_map}% +\indexlibraryctor{flat_multimap}% \begin{itemdecl} -void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); +template + constexpr flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); +template + constexpr flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const key_compare& comp, + const Alloc& a); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{key_cont.size() == mapped_cont.size()} is \tcode{true}, -the elements of \tcode{key_cont} are sorted with respect to \tcode{compare}, and -\tcode{key_cont} contains no equal elements. +\effects +Equivalent to \tcode{flat_multimap(s, key_cont, mapped_cont)} and +\tcode{flat_multimap(s, key_cont, mapped_cont, comp)}, respectively, +except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.val\-ues} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +template + constexpr explicit flat_multimap(const Alloc& a); +template + constexpr flat_multimap(const key_compare& comp, const Alloc& a); +template + constexpr flat_multimap(const flat_multimap&, const Alloc& a); +template + constexpr flat_multimap(flat_multimap&&, const Alloc& a); +template + constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a); +template + constexpr flat_multimap(InputIterator first, InputIterator last, const key_compare& comp, + const Alloc& a); +template + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); +template + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); +template + constexpr flat_multimap(initializer_list il, const Alloc& a); +template + constexpr flat_multimap(initializer_list il, const key_compare& comp, + const Alloc& a); +template + constexpr flat_multimap(sorted_equivalent_t, initializer_list il, const Alloc& a); +template + constexpr flat_multimap(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Alloc& a); +\end{itemdecl} +\begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -c.keys = std::move(key_cont); -c.values = std::move(mapped_cont); -\end{codeblock} +Equivalent to the corresponding non-allocator constructors +except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. \end{itemdescr} -\rSec3[flat.map.erasure]{Erasure} +\rSec3[flat.multimap.erasure]{Erasure} -\indexlibrarymember{erase_if}{flat_map}% +\indexlibrarymember{erase_if}{flat_multimap}% \begin{itemdecl} template - typename flat_map::size_type - erase_if(flat_map& c, Predicate pred); + constexpr typename flat_multimap::size_type + erase_if(flat_multimap& c, Predicate pred); \end{itemdecl} \begin{itemdescr} @@ -16244,598 +18778,695 @@ \end{note} \end{itemdescr} -\rSec2[flat.multimap]{Class template \tcode{flat_multimap}} +\rSec2[flat.set.syn]{Header \tcode{} synopsis}% +\indexheader{flat_set}% -\rSec3[flat.multimap.overview]{Overview} +\begin{codeblock} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} + +namespace std { + // \ref{flat.set}, class template \tcode{flat_set} + template, class KeyContainer = vector> + class flat_set; + + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + + template + struct uses_allocator, Allocator>; + + // \ref{flat.set.erasure}, erasure for \tcode{flat_set} + template + constexpr typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); + + // \ref{flat.multiset}, class template \tcode{flat_multiset} + template, class KeyContainer = vector> + class flat_multiset; + + struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; + inline constexpr sorted_equivalent_t sorted_equivalent{}; + + template + struct uses_allocator, Allocator>; + + // \ref{flat.multiset.erasure}, erasure for \tcode{flat_multiset} + template + constexpr typename flat_multiset::size_type + erase_if(flat_multiset& c, Predicate pred); +} +\end{codeblock} + +\rSec2[flat.set]{Class template \tcode{flat_set}} + +\rSec3[flat.set.overview]{Overview} \pnum -\indexlibraryglobal{flat_multimap}% -A \tcode{flat_multimap} is a container adaptor +\indexlibraryglobal{flat_set}% +A \tcode{flat_set} is a container adaptor that provides an associative container interface -that supports equivalent keys -(i.e., possibly containing multiple copies of the same key value) and -provides for fast retrieval of values of another type \tcode{T} -based on the keys. -\tcode{flat_multimap} supports iterators that meet -the \oldconcept{InputIterator} requirements and -model the -\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. +that supports unique keys +(i.e., contains at most one of each key value) and +provides for fast retrieval of the keys themselves. +\tcode{flat_set} supports iterators that model +the \libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. \pnum -A \tcode{flat_multimap} meets all of the requirements +A \tcode{flat_set} meets all of the requirements for a container\iref{container.reqmts} and for a reversible container\iref{container.rev.reqmts}, plus the optional container requirements\iref{container.opt.reqmts}. -\tcode{flat_multimap} meets the requirements of +\tcode{flat_set} meets the requirements of an associative container\iref{associative.reqmts}, except that: \begin{itemize} \item -it does not meet the requirements related to node handles\iref{container.node}, +it does not meet the requirements +related to node handles\iref{container.node.overview}, \item it does not meet the requirements related to iterator invalidation, and \item the time complexity of the operations -that insert or erase a single element from the map is linear, +that insert or erase a single element from the set +is linear, including the ones that take an insertion position iterator. \end{itemize} \begin{note} -A \tcode{flat_multimap} does not meet the additional requirements of an -allocator-aware container\iref{container.alloc.reqmts}. +A \tcode{flat_set} does not meet +the additional requirements of an allocator-aware container, +as described in \ref{container.alloc.reqmts}. \end{note} \pnum -A \tcode{flat_multimap} also provides most operations described -in \ref{associative.reqmts} for equal keys. -This means that a \tcode{flat_multimap} supports -the \tcode{a_eq} operations in \ref{associative.reqmts} -but not the \tcode{a_uniq} operations. -For a \tcode{flat_multimap} -the \tcode{key_type} is \tcode{Key} and -the \tcode{value_type} is \tcode{pair}. +A \tcode{flat_set} also provides most operations +described in \ref{associative.reqmts} for unique keys. +This means that a \tcode{flat_set} supports +the \tcode{a_uniq} operations in \ref{associative.reqmts} +but not the \tcode{a_eq} operations. +For a \tcode{flat_set}, +both the \tcode{key_type} and \tcode{value_type} are \tcode{Key}. \pnum -Except as otherwise noted, -operations on \tcode{flat_multimap} are equivalent to those of \tcode{flat_map}, -except that \tcode{flat_multimap} operations -do not remove or replace elements with equal keys. -\begin{example} -\tcode{flat_multimap} constructors and emplace do not erase -non-unique elements after sorting them. -\end{example} +Descriptions are provided here only for operations on \tcode{flat_set} +that are not described in one of those sets of requirements or +for operations where there is additional semantic information. \pnum -A \tcode{flat_multimap} maintains the following invariants: -\begin{itemize} -\item -it contains the same number of keys and values; -\item -the keys are sorted with respect to the comparison object; and -\item -the value at offset \tcode{off} within the value container is the value -associated with the key at offset \tcode{off} within the key container. -\end{itemize} +A \tcode{flat_set} maintains the invariant that the keys are sorted with +respect to the comparison object. \pnum -If any member function in \ref{flat.multimap.defn} exits via an exception, -the invariants are restored. +If any member function in \ref{flat.set.defn} exits via an exception, +the invariant is restored. \begin{note} -This can result in the \tcode{flat_multimap} being emptied. +This can result in the \tcode{flat_set}'s being emptied. \end{note} \pnum -Any type \tcode{C} -that meets the sequence container requirements\iref{sequence.reqmts} -can be used to instantiate \tcode{flat_multimap}, -as long as -\tcode{C::iterator} meets the \oldconcept{RandomAccessIterator} requirements and -invocations of -member functions \tcode{C::size} and \tcode{C::max_size} do not exit via an exception. -In particular, -\tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} can be used. +Any sequence container\iref{sequence.reqmts} +supporting \oldconcept{RandomAccessIterator} +can be used to instantiate \tcode{flat_set}. +In particular, \tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} +can be used. \begin{note} \tcode{vector} is not a sequence container. \end{note} \pnum -The program is ill-formed if -\tcode{Key} is not the same type as \tcode{KeyContainer::value_type} or -\tcode{T} is not the same type as \tcode{MappedContainer::value_type}. +The program is ill-formed if \tcode{Key} is not the same type +as \tcode{KeyContainer::value_type}. \pnum -The effect of calling a constructor -that takes both \tcode{key_container_type} and -\tcode{mapped_container_type} arguments -with containers of different sizes is undefined. +The effect of calling a constructor or member function +that takes a \tcode{sorted_unique_t} argument +with a range that is not sorted with respect to \tcode{key_comp()}, or +that contains equal elements, is undefined. \pnum -The effect of calling a constructor or member function -that takes a \tcode{sorted_equivalent_t} argument -with a container, containers, or range -that are not sorted with respect to \tcode{key_comp()} is undefined. +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. -\rSec3[flat.multimap.defn]{Definition} +\rSec3[flat.set.defn]{Definition} \begin{codeblock} namespace std { - template, - class KeyContainer = vector, class MappedContainer = vector> - class flat_multimap { + template, class KeyContainer = vector> + class @\libglobal{flat_set}@ { public: // types - using key_type = Key; - using mapped_type = T; - using value_type = pair; - using key_compare = Compare; - using reference = pair; - using const_reference = pair; - using size_type = size_t; - using difference_type = ptrdiff_t; - using iterator = @\impdefx{type of \tcode{flat_multimap::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{flat_multimap::const_iterator}}@; // see \ref{container.requirements} - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using key_container_type = KeyContainer; - using mapped_container_type = MappedContainer; - - class value_compare { - private: - key_compare comp; // \expos - value_compare(key_compare c) : comp(c) { } // \expos - - public: - bool operator()(const_reference x, const_reference y) const { - return comp(x.first, y.first); - } - }; + using key_type = Key; + using value_type = Key; + using key_compare = Compare; + using value_compare = Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename KeyContainer::size_type; + using difference_type = typename KeyContainer::difference_type; + using iterator = @\impdefx{type of \tcode{flat_set::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{flat_set::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using container_type = KeyContainer; - struct containers { - key_container_type keys; - mapped_container_type values; - }; + // \ref{flat.set.cons}, constructors + constexpr flat_set() : flat_set(key_compare()) { } - // \ref{flat.multimap.cons}, construct/copy/destroy - flat_multimap() : flat_multimap(key_compare()) { } + constexpr explicit flat_set(const key_compare& comp) + : @\exposid{c}@(), @\exposid{compare}@(comp) { } - template - flat_multimap(const flat_multimap&, const Allocator& a); - template - flat_multimap(flat_multimap&&, const Allocator& a); + constexpr explicit flat_set(container_type cont, const key_compare& comp = key_compare()); - flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); - template - flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const Allocator& a); - template - flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const key_compare& comp, const Allocator& a); - - flat_multimap(sorted_equivalent_t, - key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); - template - flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const Allocator& a); - template - flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, - const key_compare& comp, const Allocator& a); - - explicit flat_multimap(const key_compare& comp) - : c(), compare(comp) { } - template - flat_multimap(const key_compare& comp, const Allocator& a); - template - explicit flat_multimap(const Allocator& a); + constexpr flat_set(sorted_unique_t, container_type cont, + const key_compare& comp = key_compare()) + : @\exposid{c}@(std::move(cont)), @\exposid{compare}@(comp) { } template - flat_multimap(InputIterator first, InputIterator last, - const key_compare& comp = key_compare()) - : c(), compare(comp) + constexpr flat_set(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : @\exposid{c}@(), @\exposid{compare}@(comp) { insert(first, last); } - template - flat_multimap(InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_multimap(InputIterator first, InputIterator last, const Allocator& a); + + template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : @\exposid{c}@(first, last), @\exposid{compare}@(comp) { } template<@\exposconcept{container-compatible-range}@ R> - flat_multimap(from_range_t fr, R&& rg) - : flat_multimap(fr, std::forward(rg), key_compare()) { } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multimap(from_range_t, R&& rg, const Allocator& a); + constexpr flat_set(from_range_t, R&& rg) + : flat_set(from_range, std::forward(rg), key_compare()) { } template<@\exposconcept{container-compatible-range}@ R> - flat_multimap(from_range_t, R&& rg, const key_compare& comp) - : flat_multimap(comp) { insert_range(std::forward(rg)); } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); + constexpr flat_set(from_range_t, R&& rg, const key_compare& comp) + : flat_set(comp) + { insert_range(std::forward(rg)); } - template - flat_multimap(sorted_equivalent_t s, InputIterator first, InputIterator last, - const key_compare& comp = key_compare()) - : c(), compare(comp) { insert(s, first, last); } - template - flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, - const Allocator& a); - - flat_multimap(initializer_list il, const key_compare& comp = key_compare()) - : flat_multimap(il.begin(), il.end(), comp) { } - template - flat_multimap(initializer_list il, const key_compare& comp, - const Allocator& a); - template - flat_multimap(initializer_list il, const Allocator& a); - - flat_multimap(sorted_equivalent_t s, initializer_list il, - const key_compare& comp = key_compare()) - : flat_multimap(s, il.begin(), il.end(), comp) { } - template - flat_multimap(sorted_equivalent_t, initializer_list il, - const key_compare& comp, const Allocator& a); - template - flat_multimap(sorted_equivalent_t, initializer_list il, const Allocator& a); + constexpr flat_set(initializer_list il, const key_compare& comp = key_compare()) + : flat_set(il.begin(), il.end(), comp) { } + + constexpr flat_set(sorted_unique_t s, initializer_list il, + const key_compare& comp = key_compare()) + : flat_set(s, il.begin(), il.end(), comp) { } - flat_multimap& operator=(initializer_list il); + // \ref{flat.set.cons.alloc}, constructors with allocators + + template + constexpr explicit flat_set(const Alloc& a); + template + constexpr flat_set(const key_compare& comp, const Alloc& a); + template + constexpr flat_set(const container_type& cont, const Alloc& a); + template + constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, const container_type& cont, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, const container_type& cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_set(const flat_set&, const Alloc& a); + template + constexpr flat_set(flat_set&&, const Alloc& a); + template + constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_set(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_set(initializer_list il, const Alloc& a); + template + constexpr flat_set(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_set(sorted_unique_t, initializer_list il, const Alloc& a); + template + constexpr flat_set(sorted_unique_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + constexpr flat_set& operator=(initializer_list); // 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; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; - // modifiers - template iterator emplace(Args&&... args); + // \ref{flat.set.modifiers}, modifiers + template constexpr pair emplace(Args&&... args); template - iterator emplace_hint(const_iterator position, Args&&... args); + constexpr iterator emplace_hint(const_iterator position, Args&&... args); - iterator insert(const value_type& x) + constexpr pair insert(const value_type& x) { return emplace(x); } - iterator insert(value_type&& x) + constexpr pair insert(value_type&& x) { return emplace(std::move(x)); } - iterator insert(const_iterator position, const value_type& x) + template constexpr pair insert(K&& x); + constexpr iterator insert(const_iterator position, const value_type& x) { return emplace_hint(position, x); } - iterator insert(const_iterator position, value_type&& x) + constexpr iterator insert(const_iterator position, value_type&& x) { return emplace_hint(position, std::move(x)); } + template constexpr iterator insert(const_iterator hint, K&& x); - template iterator insert(P&& x); - template - iterator insert(const_iterator position, P&&); template - void insert(InputIterator first, InputIterator last); + constexpr void insert(InputIterator first, InputIterator last); template - void insert(sorted_equivalent_t, InputIterator first, InputIterator last); + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); + constexpr void insert_range(R&& rg); - void insert(initializer_list il) + constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } - void insert(sorted_equivalent_t s, initializer_list il) + constexpr void insert(sorted_unique_t s, initializer_list il) { insert(s, il.begin(), il.end()); } - containers extract() &&; - void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + constexpr container_type extract() &&; + constexpr void replace(container_type&&); - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); - void swap(flat_multimap&) noexcept; - void clear() noexcept; + constexpr void swap(flat_set& y) noexcept; + constexpr void clear() noexcept; // observers - key_compare key_comp() const; - value_compare value_comp() const; + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; - const key_container_type& keys() const noexcept { return c.keys; } - const mapped_container_type& values() const noexcept { return c.values; } - - // map operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; + // set operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; - size_type count(const key_type& x) const; - template size_type count(const K& x) const; + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; - bool contains(const key_type& x) const; - template bool contains(const K& x) const; + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; template - pair equal_range(const K& x); + constexpr pair equal_range(const K& x); template - pair equal_range(const K& x) const; + constexpr pair equal_range(const K& x) const; - friend bool operator==(const flat_multimap& x, const flat_multimap& y); + constexpr friend bool operator==(const flat_set& x, const flat_set& y); - friend @\exposid{synth-three-way-result}@ - operator<=>(const flat_multimap& x, const flat_multimap& y); + constexpr friend @\placeholder{synth-three-way-result}@ + operator<=>(const flat_set& x, const flat_set& y); - friend void swap(flat_multimap& x, flat_multimap& y) noexcept - { x.swap(y); } + constexpr friend void swap(flat_set& x, flat_set& y) noexcept { x.swap(y); } private: - containers c; // \expos - key_compare compare; // \expos + container_type @\exposidnc{c}@; // \expos + key_compare @\exposidnc{compare}@; // \expos }; - template> - flat_multimap(KeyContainer, MappedContainer, Compare = Compare()) - -> flat_multimap; + template> + flat_set(KeyContainer, Compare = Compare()) + -> flat_set; + template + flat_set(KeyContainer, Allocator) + -> flat_set, KeyContainer>; + template + flat_set(KeyContainer, Compare, Allocator) + -> flat_set; - template - flat_multimap(KeyContainer, MappedContainer, Allocator) - -> flat_multimap, KeyContainer, MappedContainer>; - template - flat_multimap(KeyContainer, MappedContainer, Compare, Allocator) - -> flat_multimap; + template> + flat_set(sorted_unique_t, KeyContainer, Compare = Compare()) + -> flat_set; + template + flat_set(sorted_unique_t, KeyContainer, Allocator) + -> flat_set, KeyContainer>; + template + flat_set(sorted_unique_t, KeyContainer, Compare, Allocator) + -> flat_set; - template> - flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare()) - -> flat_multimap; + template>> + flat_set(InputIterator, InputIterator, Compare = Compare()) + -> flat_set<@\placeholder{iter-value-type}@, Compare>; - template - flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator) - -> flat_multimap, KeyContainer, MappedContainer>; - template - flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator) - -> flat_multimap; + template>> + flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_set<@\placeholder{iter-value-type}@, Compare>; - template>> - flat_multimap(InputIterator, InputIterator, Compare = Compare()) - -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + template>, + class Allocator = allocator>> + flat_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_set, Compare, + vector, + @\exposid{alloc-rebind}@>>>; - template>> - flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) - -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + template + flat_set(from_range_t, R&&, Allocator) + -> flat_set, less>, + vector, + @\exposid{alloc-rebind}@>>>; + + template> + flat_set(initializer_list, Compare = Compare()) + -> flat_set; + + template> + flat_set(sorted_unique_t, initializer_list, Compare = Compare()) + -> flat_set; + + template + struct uses_allocator, Allocator> + : bool_constant> { }; +} +\end{codeblock} + +\rSec3[flat.set.cons]{Constructors} + +\indexlibraryctor{flat_set}% +\begin{itemdecl} +constexpr explicit flat_set(container_type cont, const key_compare& comp = key_compare()); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{c} with \tcode{std::move(cont)} and +\exposid{compare} with \tcode{comp}, +sorts the range \range{begin()}{end()} with respect to \exposid{compare}, and +finally erases all but the first element +from each group of consecutive equivalent elements. + +\pnum +\complexity +Linear in $N$ if \tcode{cont} is already sorted with respect to \exposid{compare} and +otherwise $N \log N$, where $N$ is the value of \tcode{cont.size()} before this call. +\end{itemdescr} + +\rSec3[flat.set.cons.alloc]{Constructors with allocators} + +\pnum +The constructors in this subclause shall not participate in overload resolution +unless \tcode{uses_allocator_v} is \tcode{true}. + +\indexlibraryctor{flat_set}% +\begin{itemdecl} +template + constexpr flat_set(const container_type& cont, const Alloc& a); +template + constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to +\tcode{flat_set(cont)} and \tcode{flat_set(cont, comp)}, respectively, +except that \exposid{c} is constructed with +uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Same as \tcode{flat_set(cont)} and \tcode{flat_set(cont, comp)}, respectively. +\end{itemdescr} + +\indexlibraryctor{flat_set}% +\begin{itemdecl} +template + constexpr flat_set(sorted_unique_t s, const container_type& cont, const Alloc& a); +template + constexpr flat_set(sorted_unique_t s, const container_type& cont, + const key_compare& comp, const Alloc& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to +\tcode{flat_set(s, cont)} and \tcode{flat_set(s, cont, comp)}, respectively, +except that \exposid{c} is constructed with +uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibraryctor{flat_set}% +\begin{itemdecl} +template + constexpr explicit flat_set(const Alloc& a); +template + constexpr flat_set(const key_compare& comp, const Alloc& a); +template + constexpr flat_set(const flat_set&, const Alloc& a); +template + constexpr flat_set(flat_set&&, const Alloc& a); +template + constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a); +template + constexpr flat_set(InputIterator first, InputIterator last, const key_compare& comp, + const Alloc& a); +template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a); +template + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); +template + constexpr flat_set(initializer_list il, const Alloc& a); +template + constexpr flat_set(initializer_list il, const key_compare& comp, const Alloc& a); +template + constexpr flat_set(sorted_unique_t, initializer_list il, const Alloc& a); +template + constexpr flat_set(sorted_unique_t, initializer_list il, + const key_compare& comp, const Alloc& a); +\end{itemdecl} - template>, - class Allocator = allocator> - flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) - -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare, - vector<@\exposid{range-key-type}@, - @\exposid{alloc-rebind}@>>, - vector<@\exposid{range-mapped-type}@, - @\exposid{alloc-rebind}@>>>; +\begin{itemdescr} +\pnum +\effects +Equivalent to the corresponding non-allocator constructors +except that \exposid{c} is constructed with +uses-allocator construction\iref{allocator.uses.construction}. +\end{itemdescr} - template - flat_multimap(from_range_t, R&&, Allocator) - -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, less<@\exposid{range-key-type}@>, - vector<@\exposid{range-key-type}@, - @\exposid{alloc-rebind}@>>, - vector<@\exposid{range-mapped-type}@, - @\exposid{alloc-rebind}@>>>; +\rSec3[flat.set.modifiers]{Modifiers} - template> - flat_multimap(initializer_list>, Compare = Compare()) - -> flat_multimap; +\indexlibrarymember{insert}{flat_set}% +\begin{itemdecl} +template constexpr pair insert(K&& x); +template constexpr iterator insert(const_iterator hint, K&& x); +\end{itemdecl} - template> - flat_multimap(sorted_equivalent_t, initializer_list>, Compare = Compare()) - -> flat_multimap; +\begin{itemdescr} +\pnum +\constraints +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. +\tcode{is_constructi\-ble_v} is \tcode{true}. - template - struct uses_allocator, - Allocator> - : bool_constant && - uses_allocator_v> { }; -} -\end{codeblock} +\pnum +\expects +The conversion from \tcode{x} into \tcode{value_type} constructs +an object \tcode{u}, for which \tcode{find(x) == find(u)} is \tcode{true}. \pnum -The member type \tcode{containers} has the data members and special members -specified above. It has no base classes or members other than those -specified. +\effects +If the set already contains an element equivalent to \tcode{x}, +\tcode{*this} and \tcode{x} are unchanged. +Otherwise, +inserts a new element as if by \tcode{emplace(std::forward(x))}. -\rSec3[flat.multimap.cons]{Constructors} +\pnum +\returns +In the first overload, +the \tcode{bool} component of the returned pair is \tcode{true} +if and only if the insertion took place. +The returned iterator points to the element +whose key is equivalent to \tcode{x}. +\end{itemdescr} -\indexlibraryctor{flat_multimap}% +\indexlibrarymember{insert}{flat_set}% \begin{itemdecl} -flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); +template + constexpr void insert(InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes -\tcode{c.keys} with \tcode{std::move(key_cont)}, -\tcode{c.values} with \tcode{std::move(mapped_cont)}, and -\tcode{compare} with \tcode{comp}; -sorts the range \range{begin()}{end()} with respect to \tcode{value_comp()}. +Adds elements to \exposid{c} as if by: +\begin{codeblock} +@\exposid{c}@.insert(@\exposid{c}@.end(), first, last); +\end{codeblock} +Then, +sorts the range of newly inserted elements with respect to \exposid{compare}; +merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range; and +finally erases all but the first element +from each group of consecutive equivalent elements. \pnum \complexity -Linear in $N$ if the container arguments are already sorted -with respect to \tcode{value_comp()} and otherwise $N \log N$, -where $N$ is the value of \tcode{key_cont.size()} before this call. +$N$ + $M \log M$, where $N$ is \tcode{size()} before the operation and +$M$ is \tcode{distance(first, last)}. + +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. \end{itemdescr} -\indexlibraryctor{flat_multimap}% +\indexlibrarymember{insert}{flat_set}% \begin{itemdecl} -template - flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const Allocator& a); -template - flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, - const key_compare& comp, const Allocator& a); +template + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true} and -\tcode{uses_allocator_v} is \tcode{true}. - \pnum \effects -Equivalent to \tcode{flat_multimap(key_cont, mapped_cont)} and -\tcode{flat_multimap(key_cont, \linebreak{}mapped_cont, comp)}, respectively, -except that \tcode{c.keys} and \tcode{c.values} are constructed -with uses-allocator construction\iref{allocator.uses.construction}. +Equivalent to \tcode{insert(first, last)}. \pnum \complexity -Same as \tcode{flat_multimap(key_cont, mapped_cont)} and -\tcode{flat_multimap(key_cont, \linebreak{}mapped_cont, comp)}, respectively. +Linear. \end{itemdescr} -\indexlibraryctor{flat_multimap}% +\indexlibrarymember{insert_range}{flat_set}% \begin{itemdecl} -flat_multimap(sorted_equivalent_t, key_container_type key_cont, mapped_container_type mapped_cont, - const key_compare& comp = key_compare()); +template<@\exposconcept{container-compatible-range}@ R> + constexpr void insert_range(R&& rg); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes -\tcode{c.keys} with \tcode{std::move(key_cont)}, -\tcode{c.values} with \tcode{std::move(mapped_cont)}, and -\tcode{compare} with \tcode{comp}. +Adds elements to \exposid{c} as if by: +\begin{codeblock} +for (const auto& e : rg) { + @\exposid{c}@.insert(@\exposid{c}@.end(), e); +} +\end{codeblock} +Then, +sorts the range of newly inserted elements with respect to \exposid{compare}; +merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range; and +finally erases all but the first element +from each group of consecutive equivalent elements. \pnum \complexity -Constant. +$N$ + $M \log M$, where $N$ is \tcode{size()} before the operation and $M$ +is \tcode{ranges::distance(rg)}. + +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. \end{itemdescr} -\indexlibraryctor{flat_multimap}% +\indexlibrarymember{swap}{flat_set}% \begin{itemdecl} -template - flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const Allocator& a); -template - flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const key_compare& comp, - const Allocator& a); +constexpr void swap(flat_set& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true} and -\tcode{uses_allocator_v} is \tcode{true}. +\effects +Equivalent to: +\begin{codeblock} +ranges::swap(@\exposid{compare}@, y.@\exposid{compare}@); +ranges::swap(@\exposid{c}@, y.@\exposid{c}@); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{extract}{flat_set}% +\begin{itemdecl} +constexpr container_type extract() &&; +\end{itemdecl} +\begin{itemdescr} \pnum -\effects -Equivalent to \tcode{flat_multimap(s, key_cont, mapped_cont)} and -\tcode{flat_multimap(s, key_cont, mapped_cont, comp)}, respectively, -except that \tcode{c.keys} and \tcode{c.val\-ues} are constructed -with uses-allocator construction\iref{allocator.uses.construction}. +\ensures +\tcode{*this} is emptied, even if the function exits via an exception. \pnum -\complexity -Linear. +\returns +\tcode{std::move(\exposid{c})}. \end{itemdescr} -\indexlibraryctor{flat_multimap}% +\indexlibrarymember{replace}{flat_set}% \begin{itemdecl} -template - flat_multimap(const flat_multimap&, const Allocator& a); -template - flat_multimap(flat_multimap&&, const Allocator& a); -template - flat_multimap(const key_compare& comp, const Allocator& a); -template - explicit flat_multimap(const Allocator& a); -template - flat_multimap(InputIterator first, InputIterator last, const key_compare& comp, - const Allocator& a); -template - flat_multimap(InputIterator first, InputIterator last, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multimap(from_range_t, R&& rg, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); -template - flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); -template - flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, - const Allocator& a); -template - flat_multimap(initializer_list il, const key_compare& comp, const Allocator& a); -template - flat_multimap(initializer_list il, const Allocator& a); -template - flat_multimap(sorted_equivalent_t, initializer_list il, - const key_compare& comp, const Allocator& a); -template - flat_multimap(sorted_equivalent_t, initializer_list il, const Allocator& a); +constexpr void replace(container_type&& cont); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true} and -\tcode{uses_allocator_v} is \tcode{true}. +\expects +The elements of \tcode{cont} are sorted with respect to \exposid{compare}, and +\tcode{cont} contains no equal elements. \pnum \effects -Equivalent to the corresponding non-allocator constructors -except that \tcode{c.keys} and \tcode{c.values} are constructed -with uses-allocator construction\iref{allocator.uses.construction}. +Equivalent to: \tcode{\exposid{c} = std::move(cont);} \end{itemdescr} -\rSec3[flat.multimap.erasure]{Erasure} +\rSec3[flat.set.erasure]{Erasure} -\indexlibrarymember{erase_if}{flat_multimap}% +\indexlibrarymember{erase_if}{flat_set}% \begin{itemdecl} -template - typename flat_multimap::size_type - erase_if(flat_multimap& c, Predicate pred); +template + constexpr typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{Key} and \tcode{T} meet the \oldconcept{MoveAssignable} requirements. +\tcode{Key} meets the \oldconcept{MoveAssignable} requirements. \pnum \effects -Let $E$ be \tcode{bool(pred(pair(e)))}. +Let $E$ be \tcode{bool(pred(as_const(e)))}. Erases all elements \tcode{e} in \tcode{c} for which $E$ holds. \pnum @@ -16852,31 +19483,30 @@ If an invocation of \tcode{erase_if} exits via an exception, \tcode{c} is in a valid but unspecified state\iref{defns.valid}. \begin{note} -\tcode{c} still meets its invariants, -but can be empty. +\tcode{c} still meets its invariants, but can be empty. \end{note} \end{itemdescr} -\rSec2[flat.set]{Class template \tcode{flat_set}} +\rSec2[flat.multiset]{Class template \tcode{flat_multiset}} -\rSec3[flat.set.overview]{Overview} +\rSec3[flat.multiset.overview]{Overview} \pnum -\indexlibraryglobal{flat_set}% -A \tcode{flat_set} is a container adaptor +\indexlibraryglobal{flat_multiset}% +A \tcode{flat_multiset} is a container adaptor that provides an associative container interface -that supports unique keys -(i.e., contains at most one of each key value) and +that supports equivalent keys +(i.e., possibly containing multiple copies of the same key value) and provides for fast retrieval of the keys themselves. -\tcode{flat_set} supports iterators that model -the \libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. +\tcode{flat_multiset} supports iterators that model the +\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. \pnum -A \tcode{flat_set} meets all of the requirements +A \tcode{flat_multiset} meets all of the requirements for a container\iref{container.reqmts} and for a reversible container\iref{container.rev.reqmts}, plus the optional container requirements\iref{container.opt.reqmts}. -\tcode{flat_set} meets the requirements of +\tcode{flat_multiset} meets the requirements of an associative container\iref{associative.reqmts}, except that: \begin{itemize} \item @@ -16886,47 +19516,47 @@ it does not meet the requirements related to iterator invalidation, and \item the time complexity of the operations -that insert or erase a single element from the set -is linear, +that insert or erase a single element from the +set is linear, including the ones that take an insertion position iterator. \end{itemize} \begin{note} -A \tcode{flat_set} does not meet +A \tcode{flat_multiset} does not meet the additional requirements of an allocator-aware container, as described in \ref{container.alloc.reqmts}. \end{note} \pnum -A \tcode{flat_set} also provides most operations -described in \ref{associative.reqmts} for unique keys. -This means that a \tcode{flat_set} supports -the \tcode{a_uniq} operations in \ref{associative.reqmts} -but not the \tcode{a_eq} operations. -For a \tcode{flat_set}, +A \tcode{flat_multiset} also provides most operations +described in \ref{associative.reqmts} for equal keys. +This means that a \tcode{flat_multiset} supports +the \tcode{a_eq} operations in \ref{associative.reqmts} +but not the \tcode{a_uniq} operations. +For a \tcode{flat_multiset}, both the \tcode{key_type} and \tcode{value_type} are \tcode{Key}. \pnum -Descriptions are provided here only for operations on \tcode{flat_set} -that are not described in one of those sets of requirements or +Descriptions are provided here only for operations on \tcode{flat_multiset} +that are not described in one of the general sections or for operations where there is additional semantic information. \pnum -A \tcode{flat_set} maintains the invariant that the keys are sorted with -respect to the comparison object. +A \tcode{flat_multiset} maintains the invariant +that the keys are sorted with respect to the comparison object. \pnum -If any member function in \ref{flat.set.defn} exits via an exception, +If any member function in \ref{flat.multiset.defn} exits via an exception, the invariant is restored. \begin{note} -This can result in the \tcode{flat_set}'s being emptied. +This can result in the \tcode{flat_multiset}'s being emptied. \end{note} \pnum Any sequence container\iref{sequence.reqmts} supporting \oldconcept{RandomAccessIterator} -can be used to instantiate \tcode{flat_set}. -In particular, \tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} -can be used. +can be used to instantiate \tcode{flat_multiset}. +In particular, +\tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} can be used. \begin{note} \tcode{vector} is not a sequence container. \end{note} @@ -16937,16 +19567,19 @@ \pnum The effect of calling a constructor or member function -that takes a \tcode{sorted_unique_t} argument -with a range that is not sorted with respect to \tcode{key_comp()}, or -that contains equal elements, is undefined. +that takes a \tcode{sorted_equivalent_t} argument with a range +that is not sorted with respect to \tcode{key_comp()} is undefined. -\rSec3[flat.set.defn]{Definition} +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. + +\rSec3[flat.multiset.defn]{Definition} \begin{codeblock} namespace std { template, class KeyContainer = vector> - class @\libglobal{flat_set}@ { + class flat_multiset { public: // types using key_type = Key; @@ -16957,191 +19590,200 @@ using const_reference = const value_type&; using size_type = typename KeyContainer::size_type; using difference_type = typename KeyContainer::difference_type; - using iterator = @\impdefx{type of \tcode{flat_set::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{flat_set::const_iterator}}@; // see \ref{container.requirements} + using iterator = @\impdefx{type of \tcode{flat_multiset::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{flat_multiset::const_iterator}}@; // see \ref{container.requirements} using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using container_type = KeyContainer; - // \ref{flat.set.cons}, constructors - flat_set() : flat_set(key_compare()) { } + // \ref{flat.multiset.cons}, constructors + constexpr flat_multiset() : flat_multiset(key_compare()) { } - template - flat_set(const flat_set&, const Allocator& a); - template - flat_set(flat_set&&, const Allocator& a); + constexpr explicit flat_multiset(const key_compare& comp) + : @\exposid{c}@(), @\exposid{compare}@(comp) { } - explicit flat_set(container_type cont, const key_compare& comp = key_compare()); - template - flat_set(const container_type& cont, const Allocator& a); - template - flat_set(const container_type& cont, const key_compare& comp, const Allocator& a); + constexpr explicit flat_multiset(container_type cont, + const key_compare& comp = key_compare()); - flat_set(sorted_unique_t, container_type cont, const key_compare& comp = key_compare()) + constexpr flat_multiset(sorted_equivalent_t, container_type cont, + const key_compare& comp = key_compare()) : @\exposid{c}@(std::move(cont)), @\exposid{compare}@(comp) { } - template - flat_set(sorted_unique_t, const container_type& cont, const Allocator& a); - template - flat_set(sorted_unique_t, const container_type& cont, - const key_compare& comp, const Allocator& a); - - explicit flat_set(const key_compare& comp) - : @\exposid{c}@(), @\exposid{compare}@(comp) { } - template - flat_set(const key_compare& comp, const Allocator& a); - template - explicit flat_set(const Allocator& a); template - flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()) + constexpr flat_multiset(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) : @\exposid{c}@(), @\exposid{compare}@(comp) { insert(first, last); } - template - flat_set(InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_set(InputIterator first, InputIterator last, const Allocator& a); + + template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : @\exposid{c}@(first, last), @\exposid{compare}@(comp) { } template<@\exposconcept{container-compatible-range}@ R> - flat_set(from_range_t fr, R&& rg) - : flat_set(fr, std::forward(rg), key_compare()) { } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_set(from_range_t, R&& rg, const Allocator& a); + constexpr flat_multiset(from_range_t, R&& rg) + : flat_multiset(from_range, std::forward(rg), key_compare()) { } template<@\exposconcept{container-compatible-range}@ R> - flat_set(from_range_t, R&& rg, const key_compare& comp) - : flat_set(comp) + constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp) + : flat_multiset(comp) { insert_range(std::forward(rg)); } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_set(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); - - template - flat_set(sorted_unique_t, InputIterator first, InputIterator last, - const key_compare& comp = key_compare()) - : @\exposid{c}@(first, last), @\exposid{compare}@(comp) { } - template - flat_set(sorted_unique_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); - flat_set(initializer_list il, const key_compare& comp = key_compare()) - : flat_set(il.begin(), il.end(), comp) { } - template - flat_set(initializer_list il, const key_compare& comp, const Allocator& a); - template - flat_set(initializer_list il, const Allocator& a); + constexpr flat_multiset(initializer_list il, + const key_compare& comp = key_compare()) + : flat_multiset(il.begin(), il.end(), comp) { } - flat_set(sorted_unique_t s, initializer_list il, - const key_compare& comp = key_compare()) - : flat_set(s, il.begin(), il.end(), comp) { } - template - flat_set(sorted_unique_t, initializer_list il, - const key_compare& comp, const Allocator& a); - template - flat_set(sorted_unique_t, initializer_list il, const Allocator& a); + constexpr flat_multiset(sorted_equivalent_t s, initializer_list il, + const key_compare& comp = key_compare()) + : flat_multiset(s, il.begin(), il.end(), comp) { } - flat_set& operator=(initializer_list); + // \ref{flat.multiset.cons.alloc}, constructors with allocators + + template + constexpr explicit flat_multiset(const Alloc& a); + template + constexpr flat_multiset(const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(const container_type& cont, const Alloc& a); + template + constexpr flat_multiset(const container_type& cont, const key_compare& comp, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(const flat_multiset&, const Alloc& a); + template + constexpr flat_multiset(flat_multiset&&, const Alloc& a); + template + constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a); + template + constexpr flat_multiset(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a); + template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template + constexpr flat_multiset(initializer_list il, const Alloc& a); + template + constexpr flat_multiset(initializer_list il, const key_compare& comp, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, initializer_list il, + const Alloc& a); + template + constexpr flat_multiset(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Alloc& a); + + constexpr flat_multiset& operator=(initializer_list); // 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; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; - // \ref{flat.set.modifiers}, modifiers - template pair emplace(Args&&... args); + // \ref{flat.multiset.modifiers}, modifiers + template constexpr iterator emplace(Args&&... args); template - iterator emplace_hint(const_iterator position, Args&&... args); + constexpr iterator emplace_hint(const_iterator position, Args&&... args); - pair insert(const value_type& x) + constexpr iterator insert(const value_type& x) { return emplace(x); } - pair insert(value_type&& x) + constexpr iterator insert(value_type&& x) { return emplace(std::move(x)); } - template pair insert(K&& x); - iterator insert(const_iterator position, const value_type& x) + constexpr iterator insert(const_iterator position, const value_type& x) { return emplace_hint(position, x); } - iterator insert(const_iterator position, value_type&& x) + constexpr iterator insert(const_iterator position, value_type&& x) { return emplace_hint(position, std::move(x)); } - template iterator insert(const_iterator hint, K&& x); template - void insert(InputIterator first, InputIterator last); + constexpr void insert(InputIterator first, InputIterator last); template - void insert(sorted_unique_t, InputIterator first, InputIterator last); + constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); + constexpr void insert_range(R&& rg); - void insert(initializer_list il) + constexpr void insert(initializer_list il) { insert(il.begin(), il.end()); } - void insert(sorted_unique_t s, initializer_list il) + constexpr void insert(sorted_equivalent_t s, initializer_list il) { insert(s, il.begin(), il.end()); } - container_type extract() &&; - void replace(container_type&&); + constexpr container_type extract() &&; + constexpr void replace(container_type&&); - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); - void swap(flat_set& y) noexcept; - void clear() noexcept; + constexpr void swap(flat_multiset& y) noexcept; + constexpr void clear() noexcept; // observers - key_compare key_comp() const; - value_compare value_comp() const; + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; // set operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template constexpr iterator find(const K& x); + template constexpr const_iterator find(const K& x) const; - size_type count(const key_type& x) const; - template size_type count(const K& x) const; + constexpr size_type count(const key_type& x) const; + template constexpr size_type count(const K& x) const; - bool contains(const key_type& x) const; - template bool contains(const K& x) const; + constexpr bool contains(const key_type& x) const; + template constexpr bool contains(const K& x) const; - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template constexpr iterator lower_bound(const K& x); + template constexpr const_iterator lower_bound(const K& x) const; - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template constexpr iterator upper_bound(const K& x); + template constexpr const_iterator upper_bound(const K& x) const; - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; + constexpr pair equal_range(const key_type& x); + constexpr pair equal_range(const key_type& x) const; template - pair equal_range(const K& x); + constexpr pair equal_range(const K& x); template - pair equal_range(const K& x) const; + constexpr pair equal_range(const K& x) const; - friend bool operator==(const flat_set& x, const flat_set& y); + constexpr friend bool operator==(const flat_multiset& x, const flat_multiset& y); friend @\placeholder{synth-three-way-result}@ - operator<=>(const flat_set& x, const flat_set& y); + constexpr operator<=>(const flat_multiset& x, const flat_multiset& y); - friend void swap(flat_set& x, flat_set& y) noexcept { x.swap(y); } + constexpr friend void swap(flat_multiset& x, flat_multiset& y) noexcept + { x.swap(y); } private: container_type @\exposidnc{c}@; // \expos @@ -17149,127 +19791,124 @@ }; template> - flat_set(KeyContainer, Compare = Compare()) - -> flat_set; + flat_multiset(KeyContainer, Compare = Compare()) + -> flat_multiset; template - flat_set(KeyContainer, Allocator) - -> flat_set, KeyContainer>; + flat_multiset(KeyContainer, Allocator) + -> flat_multiset, KeyContainer>; template - flat_set(KeyContainer, Compare, Allocator) - -> flat_set; + flat_multiset(KeyContainer, Compare, Allocator) + -> flat_multiset; template> - flat_set(sorted_unique_t, KeyContainer, Compare = Compare()) - -> flat_set; + flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare()) + -> flat_multiset; template - flat_set(sorted_unique_t, KeyContainer, Allocator) - -> flat_set, KeyContainer>; + flat_multiset(sorted_equivalent_t, KeyContainer, Allocator) + -> flat_multiset, KeyContainer>; template - flat_set(sorted_unique_t, KeyContainer, Compare, Allocator) - -> flat_set; + flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator) + -> flat_multiset; template>> - flat_set(InputIterator, InputIterator, Compare = Compare()) - -> flat_set<@\placeholder{iter-value-type}@, Compare>; + flat_multiset(InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset<@\placeholder{iter-value-type}@, Compare>; template>> - flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) - -> flat_set<@\placeholder{iter-value-type}@, Compare>; + flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset<@\placeholder{iter-value-type}@, Compare>; template>, class Allocator = allocator>> - flat_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) - -> flat_set, Compare, - vector, - @\exposid{alloc-rebind}@>>>; + flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multiset, Compare, + vector, + @\exposid{alloc-rebind}@>>>; template - flat_set(from_range_t, R&&, Allocator) - -> flat_set, less>, - vector, - @\exposid{alloc-rebind}@>>>; + flat_multiset(from_range_t, R&&, Allocator) + -> flat_multiset, less>, + vector, + @\exposid{alloc-rebind}@>>>; template> - flat_set(initializer_list, Compare = Compare()) - -> flat_set; + flat_multiset(initializer_list, Compare = Compare()) + -> flat_multiset; template> - flat_set(sorted_unique_t, initializer_list, Compare = Compare()) - -> flat_set; + flat_multiset(sorted_equivalent_t, initializer_list, Compare = Compare()) + -> flat_multiset; template - struct uses_allocator, Allocator> + struct uses_allocator, Allocator> : bool_constant> { }; } \end{codeblock} -\rSec3[flat.set.cons]{Constructors} +\rSec3[flat.multiset.cons]{Constructors} -\indexlibraryctor{flat_set}% +\indexlibraryctor{flat_multiset}% \begin{itemdecl} -explicit flat_set(container_type cont, const key_compare& comp = key_compare()); +constexpr explicit flat_multiset(container_type cont, const key_compare& comp = key_compare()); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \exposid{c} with \tcode{std::move(cont)} and -\exposid{compare} with \tcode{comp}, -sorts the range \range{begin()}{end()} with respect to \exposid{compare}, and -finally erases all but the first element -from each group of consecutive equivalent elements. +\exposid{compare} with \tcode{comp}, and +sorts the range \range{begin()}{end()} with respect to \exposid{compare}. \pnum \complexity -Linear in $N$ if \tcode{cont} is sorted with respect to \exposid{compare} and +Linear in $N$ if \tcode{cont} is already sorted with respect to \exposid{compare} and otherwise $N \log N$, where $N$ is the value of \tcode{cont.size()} before this call. \end{itemdescr} -\indexlibraryctor{flat_set}% +\rSec3[flat.multiset.cons.alloc]{Constructors with allocators} + +\pnum +The constructors in this subclause shall not participate in overload resolution +unless \tcode{uses_allocator_v} is \tcode{true}. + +\indexlibraryctor{flat_multiset}% \begin{itemdecl} -template - flat_set(const container_type& cont, const Allocator& a); -template - flat_set(const container_type& cont, const key_compare& comp, const Allocator& a); +template + constexpr flat_multiset(const container_type& cont, const Alloc& a); +template + constexpr flat_multiset(const container_type& cont, const key_compare& comp, const Alloc& a); \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true}. - \pnum \effects -Equivalent to -\tcode{flat_set(cont)} and \tcode{flat_set(cont, comp)}, respectively, +Equivalent to \tcode{flat_multiset(cont)} and +\tcode{flat_multiset(cont, comp)}, respectively, except that \exposid{c} is constructed with uses-allocator construction\iref{allocator.uses.construction}. \pnum \complexity -Same as \tcode{flat_set(cont)} and \tcode{flat_set(cont, comp)}, respectively. +Same as \tcode{flat_multiset(cont)} and +\tcode{flat_multiset(cont, comp)}, respectively. \end{itemdescr} -\indexlibraryctor{flat_set}% +\indexlibraryctor{flat_multiset}% \begin{itemdecl} -template - flat_set(sorted_unique_t s, const container_type& cont, const Allocator& a); -template - flat_set(sorted_unique_t s, const container_type& cont, - const key_compare& comp, const Allocator& a); +template + constexpr flat_multiset(sorted_equivalent_t s, const container_type& cont, const Alloc& a); +template + constexpr flat_multiset(sorted_equivalent_t s, const container_type& cont, + const key_compare& comp, const Alloc& a); \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true}. - \pnum \effects -Equivalent to -\tcode{flat_set(s, cont)} and \tcode{flat_set(s, cont, comp)}, respectively, +Equivalent to \tcode{flat_multiset(s, cont)} and +\tcode{flat_multiset(s, cont, comp)}, respectively, except that \exposid{c} is constructed with uses-allocator construction\iref{allocator.uses.construction}. @@ -17278,45 +19917,44 @@ Linear. \end{itemdescr} -\indexlibraryctor{flat_set}% +\indexlibraryctor{flat_multiset}% \begin{itemdecl} -template - flat_set(const flat_set&, const Allocator& a); -template - flat_set(flat_set&&, const Allocator& a); -template - flat_set(const key_compare& comp, const Allocator& a); -template - explicit flat_set(const Allocator& a); -template - flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); -template - flat_set(InputIterator first, InputIterator last, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_set(from_range_t, R&& rg, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_set(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); -template - flat_set(sorted_unique_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); -template - flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); -template - flat_set(initializer_list il, const key_compare& comp, const Allocator& a); -template - flat_set(initializer_list il, const Allocator& a); -template - flat_set(sorted_unique_t, initializer_list il, - const key_compare& comp, const Allocator& a); -template - flat_set(sorted_unique_t, initializer_list il, const Allocator& a); +template + constexpr explicit flat_multiset(const Alloc& a); +template + constexpr flat_multiset(const key_compare& comp, const Alloc& a); +template + constexpr flat_multiset(const flat_multiset&, const Alloc& a); +template + constexpr flat_multiset(flat_multiset&&, const Alloc& a); +template + constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a); +template + constexpr flat_multiset(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); +template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); +template + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a); +template<@\exposconcept{container-compatible-range}@ R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); +template + constexpr flat_multiset(initializer_list il, const Alloc& a); +template + constexpr flat_multiset(initializer_list il, const key_compare& comp, + const Alloc& a); +template + constexpr flat_multiset(sorted_equivalent_t, initializer_list il, const Alloc& a); +template + constexpr flat_multiset(sorted_equivalent_t, initializer_list il, + const key_compare& comp, const Alloc& a); \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true}. - \pnum \effects Equivalent to the corresponding non-allocator constructors @@ -17324,46 +19962,37 @@ uses-allocator construction\iref{allocator.uses.construction}. \end{itemdescr} -\rSec3[flat.set.modifiers]{Modifiers} +\rSec3[flat.multiset.modifiers]{Modifiers} -\indexlibrarymember{insert}{flat_set}% +\indexlibrarymember{emplace}{flat_multiset}% \begin{itemdecl} -template pair insert(K&& x); -template iterator insert(const_iterator hint, K&& x); +template constexpr iterator emplace(Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \constraints -The \grammarterm{qualified-id} \tcode{Compare::is_transparent} -is valid and denotes a type. -\tcode{is_constructi\-ble_v} is \tcode{true}. - -\pnum -\expects -The conversion from \tcode{x} into \tcode{value_type} constructs -an object \tcode{u}, for which \tcode{find(x) == find(u)} is true. +\tcode{is_constructible_v} is \tcode{true}. \pnum \effects -If the set already contains an element equivalent to \tcode{x}, -\tcode{*this} and \tcode{x} are unchanged. -Otherwise, -inserts a new element as if by \tcode{emplace(std::forward(x))}. +First, initializes an object \tcode{t} of type \tcode{value_type} +with \tcode{std::forward(args)...}, +then inserts \tcode{t} as if by: +\begin{codeblock} +auto it = ranges::upper_bound(@\exposid{c}@, t, @\exposid{compare}@); +@\exposid{c}@.insert(it, std::move(t)); +\end{codeblock} \pnum \returns -In the first overload, -the \tcode{bool} component of the returned pair is \tcode{true} -if and only if the insertion took place. -The returned iterator points to the element -whose key is equivalent to \tcode{x}. +An iterator that points to the inserted element. \end{itemdescr} -\indexlibrarymember{insert}{flatset}% +\indexlibrarymember{insert}{flat_multiset}% \begin{itemdecl} template - void insert(InputIterator first, InputIterator last); + constexpr void insert(InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} @@ -17373,27 +20002,24 @@ \begin{codeblock} @\exposid{c}@.insert(@\exposid{c}@.end(), first, last); \end{codeblock} -Then, -sorts the range of newly inserted elements with respect to \exposid{compare}; -merges the resulting sorted range and -the sorted range of pre-existing elements into a single sorted range; and -finally erases all but the first element -from each group of consecutive equivalent elements. +Then, sorts the range of newly inserted elements with respect to \exposid{compare}, +and merges the resulting sorted range and +the sorted range of pre-existing elements into a single sorted range. \pnum \complexity -$N$ + $M \log M$, where $N$ is \tcode{size()} before the operation and -$M$ is \tcode{distance(first, last)}. +$N$ + $M \log M$, where $N$ is \tcode{size()} before the operation and $M$ +is \tcode{distance(first, last)}. \pnum \remarks Since this operation performs an in-place merge, it may allocate memory. \end{itemdescr} -\indexlibrarymember{insert}{flat_set}% +\indexlibrarymember{insert}{flat_multiset}% \begin{itemdecl} template - void insert(sorted_unique_t, InputIterator first, InputIterator last); + constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} @@ -17406,41 +20032,9 @@ Linear. \end{itemdescr} -\indexlibrarymember{insert_range}{flat_set}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Adds elements to \exposid{c} as if by: -\begin{codeblock} -for (const auto& e : rg) { - @\exposid{c}@.insert(@\exposid{c}@.end(), e); -} -\end{codeblock} -Then, -sorts the range of newly inserted elements with respect to \exposid{compare}; -merges the resulting sorted range and -the sorted range of pre-existing elements into a single sorted range; and -finally erases all but the first element -from each group of consecutive equivalent elements. - -\pnum -\complexity -$N$ + $M \log M$, where $N$ is \tcode{size()} before the operation and $M$ -is \tcode{ranges::distance(rg)}. - -\pnum -\remarks -Since this operation performs an in-place merge, it may allocate memory. -\end{itemdescr} - -\indexlibrarymember{swap}{flat_set}% +\indexlibrarymember{swap}{flat_multiset}% \begin{itemdecl} -void swap(flat_set& y) noexcept; +constexpr void swap(flat_multiset& y) noexcept; \end{itemdecl} \begin{itemdescr} @@ -17453,9 +20047,9 @@ \end{codeblock} \end{itemdescr} -\indexlibrarymember{extract}{flatset}% +\indexlibrarymember{extract}{flat_multiset}% \begin{itemdecl} -container_type extract() &&; +constexpr container_type extract() &&; \end{itemdecl} \begin{itemdescr} @@ -17468,29 +20062,28 @@ \tcode{std::move(\exposid{c})}. \end{itemdescr} -\indexlibrarymember{replace}{flat_set}% +\indexlibrarymember{replace}{flat_multiset}% \begin{itemdecl} -void replace(container_type&& cont); +constexpr void replace(container_type&& cont); \end{itemdecl} \begin{itemdescr} \pnum \expects -The elements of \tcode{cont} are sorted with respect to \exposid{compare}, and -\tcode{cont} contains no equal elements. +The elements of \tcode{cont} are sorted with respect to \exposid{compare}. \pnum \effects Equivalent to: \tcode{\exposid{c} = std::move(cont);} \end{itemdescr} -\rSec3[flat.set.erasure]{Erasure} +\rSec3[flat.multiset.erasure]{Erasure} -\indexlibrarymember{erase_if}{flat_set}% +\indexlibrarymember{erase_if}{flat_multiset}% \begin{itemdecl} template - typename flat_set::size_type - erase_if(flat_set& c, Predicate pred); + constexpr typename flat_multiset::size_type + erase_if(flat_multiset& c, Predicate pred); \end{itemdecl} \begin{itemdescr} @@ -17521,1814 +20114,1979 @@ \end{note} \end{itemdescr} -\rSec2[flat.multiset]{Class template \tcode{flat_multiset}} - -\rSec3[flat.multiset.overview]{Overview} +\rSec2[container.adaptors.format]{Container adaptors formatting} \pnum -\indexlibraryglobal{flat_multiset}% -A \tcode{flat_multiset} is a container adaptor -that provides an associative container interface -that supports equivalent keys -(i.e., possibly containing multiple copies of the same key value) and -provides for fast retrieval of the keys themselves. -\tcode{flat_multiset} supports iterators that model the -\libconcept{random_access_iterator} concept\iref{iterator.concept.random.access}. +For each of +\tcode{queue}, +\tcode{priority_queue}, and +\tcode{stack}, +the library provides the following formatter specialization +where \tcode{\placeholder{adaptor-type}} is the name of the template: -\pnum -A \tcode{flat_multiset} meets all of the requirements -for a container\iref{container.reqmts} and -for a reversible container\iref{container.rev.reqmts}, -plus the optional container requirements\iref{container.opt.reqmts}. -\tcode{flat_multiset} meets the requirements of -an associative container\iref{associative.reqmts}, except that: -\begin{itemize} -\item -it does not meet the requirements -related to node handles\iref{container.node.overview}, -\item -it does not meet the requirements related to iterator invalidation, and -\item -the time complexity of the operations -that insert or erase a single element from the -set is linear, -including the ones that take an insertion position iterator. -\end{itemize} -\begin{note} -A \tcode{flat_multiset} does not meet -the additional requirements of an allocator-aware container, -as described in \ref{container.alloc.reqmts}. -\end{note} +\indexlibraryglobal{formatter}% +\begin{codeblock} +namespace std { + template Container, class... U> + struct formatter<@\placeholder{adaptor-type}@, charT> { + private: + using @\exposid{maybe-const-container}@ = // \expos + @\exposid{fmt-maybe-const}@; + using @\exposid{maybe-const-adaptor}@ = // \expos + @\exposid{maybe-const}@, // see \ref{ranges.syn} + @\placeholder{adaptor-type}@>; + formatter, charT> @\exposid{underlying_}@; // \expos -\pnum -A \tcode{flat_multiset} also provides most operations -described in \ref{associative.reqmts} for equal keys. -This means that a \tcode{flat_multiset} supports -the \tcode{a_eq} operations in \ref{associative.reqmts} -but not the \tcode{a_uniq} operations. -For a \tcode{flat_multiset}, -both the \tcode{key_type} and \tcode{value_type} are \tcode{Key}. + public: + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); -\pnum -Descriptions are provided here only for operations on \tcode{flat_multiset} -that are not described in one of the general sections or -for operations where there is additional semantic information. + template + typename FormatContext::iterator + format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; + }; +} +\end{codeblock} -\pnum -A \tcode{flat_multiset} maintains the invariant -that the keys are sorted with respect to the comparison object. +\indexlibrarymember{parse}{formatter}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} +\begin{itemdescr} \pnum -If any member function in \ref{flat.multiset.defn} exits via an exception, -the invariant is restored. -\begin{note} -This can result in the \tcode{flat_multiset}'s being emptied. -\end{note} +\effects +Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +\end{itemdescr} -\pnum -Any sequence container\iref{sequence.reqmts} -supporting \oldconcept{RandomAccessIterator} -can be used to instantiate \tcode{flat_multiset}. -In particular, -\tcode{vector}\iref{vector} and \tcode{deque}\iref{deque} can be used. -\begin{note} -\tcode{vector} is not a sequence container. -\end{note} +\indexlibrarymember{format}{formatter}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; +\end{itemdecl} +\begin{itemdescr} \pnum -The program is ill-formed if \tcode{Key} is not the same type -as \tcode{KeyContainer::value_type}. +\effects +Equivalent to: \tcode{return \exposid{underlying_}.format(r.c, ctx);} +\end{itemdescr} + +\rSec1[views]{Views} + +\rSec2[views.general]{General} \pnum -The effect of calling a constructor or member function -that takes a \tcode{sorted_equivalent_t} argument with a range -that is not sorted with respect to \tcode{key_comp()} is undefined. +The header \libheaderref{span} defines the view \tcode{span}. +The header \libheaderref{mdspan} defines the class template \tcode{mdspan} and +other facilities for interacting with these multidimensional views. -\rSec3[flat.multiset.defn]{Definition} +\rSec2[views.contiguous]{Contiguous access} +\rSec3[span.syn]{Header \tcode{} synopsis}% + +\indexheader{span}% \begin{codeblock} +#include // see \ref{initializer.list.syn} + +// mostly freestanding namespace std { - template, class KeyContainer = vector> - class flat_multiset { - public: - // types - using key_type = Key; - using value_type = Key; - using key_compare = Compare; - using value_compare = Compare; - using reference = value_type&; - using const_reference = const value_type&; - using size_type = typename KeyContainer::size_type; - using difference_type = typename KeyContainer::difference_type; - using iterator = @\impdefx{type of \tcode{flat_multiset::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{flat_multiset::const_iterator}}@; // see \ref{container.requirements} - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using container_type = KeyContainer; + // constants + inline constexpr size_t @\libglobal{dynamic_extent}@ = numeric_limits::max(); - // \ref{flat.multiset.cons}, constructors - flat_multiset() : flat_multiset(key_compare()) { } + template + concept @\defexposconcept{integral-constant-like}@ = // \expos + is_integral_v && + !is_same_v> && + @\libconcept{convertible_to}@ && + @\libconcept{equality_comparable_with}@ && + bool_constant::value && + bool_constant(T()) == T::value>::value; - template - flat_multiset(const flat_multiset&, const Allocator& a); - template - flat_multiset(flat_multiset&&, const Allocator& a); + template + constexpr size_t @\defexposconcept{maybe-static-ext}@ = dynamic_extent; // \expos + template<@\exposconcept{integral-constant-like}@ T> + constexpr size_t @\exposconcept{maybe-static-ext}@ = {T::value}; - explicit flat_multiset(container_type cont, const key_compare& comp = key_compare()); - template - flat_multiset(const container_type& cont, const Allocator& a); - template - flat_multiset(const container_type& cont, const key_compare& comp, const Allocator& a); + // \ref{views.span}, class template \tcode{span} + template + class span; // partially freestanding - flat_multiset(sorted_equivalent_t, container_type cont, - const key_compare& comp = key_compare()) - : @\exposid{c}@(std::move(cont)), @\exposid{compare}@(comp) { } - template - flat_multiset(sorted_equivalent_t, const container_type& cont, const Allocator& a); - template - flat_multiset(sorted_equivalent_t, const container_type& cont, - const key_compare& comp, const Allocator& a); + template + constexpr bool ranges::@\libspec{enable_view}{span}@> = true; + template + constexpr bool ranges::@\libspec{enable_borrowed_range}{span}@> = true; - explicit flat_multiset(const key_compare& comp) - : @\exposid{c}@(), @\exposid{compare}@(comp) { } - template - flat_multiset(const key_compare& comp, const Allocator& a); - template - explicit flat_multiset(const Allocator& a); + // \ref{span.objectrep}, views of object representation + template + span + as_bytes(span s) noexcept; - template - flat_multiset(InputIterator first, InputIterator last, - const key_compare& comp = key_compare()) - : @\exposid{c}@(), @\exposid{compare}@(comp) - { insert(first, last); } - template - flat_multiset(InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_multiset(InputIterator first, InputIterator last, const Allocator& a); + template + span + as_writable_bytes(span s) noexcept; +} +\end{codeblock} - template<@\exposconcept{container-compatible-range}@ R> - flat_multiset(from_range_t fr, R&& rg) - : flat_multiset(fr, std::forward(rg), key_compare()) { } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multiset(from_range_t, R&& rg, const Allocator& a); - template<@\exposconcept{container-compatible-range}@ R> - flat_multiset(from_range_t, R&& rg, const key_compare& comp) - : flat_multiset(comp) - { insert_range(std::forward(rg)); } - template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); +\rSec3[views.span]{Class template \tcode{span}} - template - flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, - const key_compare& comp = key_compare()) - : @\exposid{c}@(first, last), @\exposid{compare}@(comp) { } - template - flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); - template - flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, - const Allocator& a); - - flat_multiset(initializer_list il, const key_compare& comp = key_compare()) - : flat_multiset(il.begin(), il.end(), comp) { } - template - flat_multiset(initializer_list il, const key_compare& comp, - const Allocator& a); - template - flat_multiset(initializer_list il, const Allocator& a); - - flat_multiset(sorted_equivalent_t s, initializer_list il, - const key_compare& comp = key_compare()) - : flat_multiset(s, il.begin(), il.end(), comp) { } - template - flat_multiset(sorted_equivalent_t, initializer_list il, - const key_compare& comp, const Allocator& a); - template - flat_multiset(sorted_equivalent_t, initializer_list il, const Allocator& a); +\rSec4[span.overview]{Overview} - flat_multiset& operator=(initializer_list); +\pnum +\indexlibraryglobal{span}% +A \tcode{span} is a view over a contiguous sequence of objects, +the storage of which is owned by some other object. - // iterators - iterator begin() noexcept; - const_iterator begin() const noexcept; - iterator end() noexcept; - const_iterator end() const noexcept; +\pnum +All member functions of \tcode{span} have constant time complexity. + +\indexlibraryglobal{span}% +\begin{codeblock} +namespace std { + template + class span { + public: + // constants and types + using element_type = ElementType; + using value_type = remove_cv_t; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = element_type*; + using const_pointer = const element_type*; + using reference = element_type&; + using const_reference = const element_type&; + using iterator = @\impdefx{type of \tcode{span::iterator}}@; // see \ref{span.iterators} + using const_iterator = std::const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::const_iterator; + static constexpr size_type extent = Extent; + + // \ref{span.cons}, constructors, copy, and assignment + constexpr span() noexcept; + template + constexpr explicit(extent != dynamic_extent) span(It first, size_type count); + template + constexpr explicit(extent != dynamic_extent) span(It first, End last); + template + constexpr span(type_identity_t (&arr)[N]) noexcept; + template + constexpr span(array& arr) noexcept; + template + constexpr span(const array& arr) noexcept; + template + constexpr explicit(extent != dynamic_extent) span(R&& r); + constexpr explicit(extent != dynamic_extent) span(std::initializer_list il); + constexpr span(const span& other) noexcept = default; + template + constexpr explicit(@\seebelow@) span(const span& s) noexcept; + + constexpr span& operator=(const span& other) noexcept = default; + + // \ref{span.sub}, subviews + template + constexpr span first() const; + template + constexpr span last() const; + template + constexpr span subspan() const; + + constexpr span first(size_type count) const; + constexpr span last(size_type count) const; + constexpr span subspan( + size_type offset, size_type count = dynamic_extent) const; - reverse_iterator rbegin() noexcept; - const_reverse_iterator rbegin() const noexcept; - reverse_iterator rend() noexcept; - const_reverse_iterator rend() const noexcept; + // \ref{span.obs}, observers + constexpr size_type size() const noexcept; + constexpr size_type size_bytes() const noexcept; + constexpr bool empty() const noexcept; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() const noexcept; + // \ref{span.elem}, element access + constexpr reference operator[](size_type idx) const; + constexpr reference at(size_type idx) const; // freestanding-deleted + constexpr reference front() const; + constexpr reference back() const; + constexpr pointer data() const noexcept; - // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; + // \ref{span.iterators}, iterator support + constexpr iterator begin() const noexcept; + constexpr iterator end() const noexcept; + constexpr const_iterator cbegin() const noexcept { return begin(); } + constexpr const_iterator cend() const noexcept { return end(); } + constexpr reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } + constexpr const_reverse_iterator crend() const noexcept { return rend(); } - // \ref{flat.multiset.modifiers}, modifiers - template iterator emplace(Args&&... args); - template - iterator emplace_hint(const_iterator position, Args&&... args); + private: + pointer @\exposid{data_}@; // \expos + size_type @\exposid{size_}@; // \expos + }; - iterator insert(const value_type& x) - { return emplace(x); } - iterator insert(value_type&& x) - { return emplace(std::move(x)); } - iterator insert(const_iterator position, const value_type& x) - { return emplace_hint(position, x); } - iterator insert(const_iterator position, value_type&& x) - { return emplace_hint(position, std::move(x)); } + template + span(It, EndOrSize) -> span>, + @\exposconcept{maybe-static-ext}@>; + template + span(T (&)[N]) -> span; + template + span(array&) -> span; + template + span(const array&) -> span; + template + span(R&&) -> span>>; +} +\end{codeblock} - template - void insert(InputIterator first, InputIterator last); - template - void insert(sorted_equivalent_t, InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - void insert_range(R&& rg); +\pnum +\tcode{span} is +a trivially copyable type\iref{term.trivially.copyable.type}. - void insert(initializer_list il) - { insert(il.begin(), il.end()); } - void insert(sorted_equivalent_t s, initializer_list il) - { insert(s, il.begin(), il.end()); } +\pnum +\tcode{ElementType} is required to be +a complete object type that is not an abstract class type. - container_type extract() &&; - void replace(container_type&&); +\pnum +For a \tcode{span} \tcode{s}, +any operation that invalidates a pointer in +the range \range{s.data()}{s.data() + s.size()} +invalidates pointers, iterators, and references to elements of \tcode{s}. - iterator erase(iterator position); - iterator erase(const_iterator position); - size_type erase(const key_type& x); - template size_type erase(K&& x); - iterator erase(const_iterator first, const_iterator last); +\rSec4[span.cons]{Constructors, copy, and assignment} - void swap(flat_multiset& y) noexcept; - void clear() noexcept; +\indexlibraryctor{span}% +\begin{itemdecl} +constexpr span() noexcept; +\end{itemdecl} - // observers - key_compare key_comp() const; - value_compare value_comp() const; +\begin{itemdescr} +\pnum +\constraints +\tcode{Extent == dynamic_extent || Extent == 0} is \tcode{true}. - // set operations - iterator find(const key_type& x); - const_iterator find(const key_type& x) const; - template iterator find(const K& x); - template const_iterator find(const K& x) const; +\pnum +\ensures +%FIXME: Should "is \tcode{true}" be appended here? +\tcode{size() == 0 \&\& data() == nullptr}. +\end{itemdescr} - size_type count(const key_type& x) const; - template size_type count(const K& x) const; +\indexlibraryctor{span}% +\begin{itemdecl} +template + constexpr explicit(extent != dynamic_extent) span(It first, size_type count); +\end{itemdecl} - bool contains(const key_type& x) const; - template bool contains(const K& x) const; +\begin{itemdescr} +\pnum +\constraints +Let \tcode{U} be \tcode{remove_reference_t>}. +\begin{itemize} +\item \tcode{It} satisfies \libconcept{contiguous_iterator}. +\item +\tcode{is_convertible_v} is \tcode{true}. +\begin{note} +The intent is to allow only qualification conversions +of the iterator reference type to \tcode{element_type}. +\end{note} +\end{itemize} - iterator lower_bound(const key_type& x); - const_iterator lower_bound(const key_type& x) const; - template iterator lower_bound(const K& x); - template const_iterator lower_bound(const K& x) const; +\pnum +\expects +\begin{itemize} +\item \range{first}{first + count} is a valid range. +\item \tcode{It} models \libconcept{contiguous_iterator}. +\end{itemize} - iterator upper_bound(const key_type& x); - const_iterator upper_bound(const key_type& x) const; - template iterator upper_bound(const K& x); - template const_iterator upper_bound(const K& x) const; +\pnum +\hardexpects +If \tcode{extent} is not equal to \tcode{dynamic_extent}, +then \tcode{count == extent} is \tcode{true}. - pair equal_range(const key_type& x); - pair equal_range(const key_type& x) const; - template - pair equal_range(const K& x); - template - pair equal_range(const K& x) const; +\pnum +\effects +Initializes \exposid{data_} with \tcode{to_address(first)} and +\exposid{size_} with \tcode{count}. - friend bool operator==(const flat_multiset& x, const flat_multiset& y); +\pnum +\throws +Nothing. +\end{itemdescr} - friend @\placeholder{synth-three-way-result}@ - operator<=>(const flat_multiset& x, const flat_multiset& y); +\indexlibraryctor{span}% +\begin{itemdecl} +template + constexpr explicit(extent != dynamic_extent) span(It first, End last); +\end{itemdecl} - friend void swap(flat_multiset& x, flat_multiset& y) noexcept - { x.swap(y); } +\begin{itemdescr} +\pnum +\constraints +Let \tcode{U} be \tcode{remove_reference_t>}. +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}. +\begin{note} +The intent is to allow only qualification conversions +of the iterator reference type to \tcode{element_type}. +\end{note} +\item \tcode{It} satisfies \libconcept{contiguous_iterator}. +\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. +\item \tcode{is_convertible_v} is \tcode{false}. +\end{itemize} - private: - container_type @\exposidnc{c}@; // \expos - key_compare @\exposidnc{compare}@; // \expos - }; +\pnum +\expects +\begin{itemize} +\item \range{first}{last} is a valid range. +\item \tcode{It} models \libconcept{contiguous_iterator}. +\item \tcode{End} models \tcode{\libconcept{sized_sentinel_for}}. +\end{itemize} - template> - flat_multiset(KeyContainer, Compare = Compare()) - -> flat_multiset; - template - flat_multiset(KeyContainer, Allocator) - -> flat_multiset, KeyContainer>; - template - flat_multiset(KeyContainer, Compare, Allocator) - -> flat_multiset; +\pnum +\hardexpects +If \tcode{extent} is not equal to \tcode{dynamic_extent}, +then \tcode{(last - first) == extent} is \tcode{true}. - template> - flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare()) - -> flat_multiset; - template - flat_multiset(sorted_equivalent_t, KeyContainer, Allocator) - -> flat_multiset, KeyContainer>; - template - flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator) - -> flat_multiset; +\pnum +\effects +Initializes \exposid{data_} with \tcode{to_address(first)} and +\exposid{size_} with \tcode{last - first}. - template>> - flat_multiset(InputIterator, InputIterator, Compare = Compare()) - -> flat_multiset<@\placeholder{iter-value-type}@, Compare>; +\pnum +\throws +When and what \tcode{last - first} throws. +\end{itemdescr} - template>> - flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) - -> flat_multiset<@\placeholder{iter-value-type}@, Compare>; +\indexlibraryctor{span}% +\begin{itemdecl} +template constexpr span(type_identity_t (&arr)[N]) noexcept; +template constexpr span(array& arr) noexcept; +template constexpr span(const array& arr) noexcept; +\end{itemdecl} - template>, - class Allocator = allocator>> - flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) - -> flat_multiset, Compare, - vector, - @\exposid{alloc-rebind}@>>>; +\begin{itemdescr} +\pnum +\constraints +Let \tcode{U} be \tcode{remove_pointer_t}. +\begin{itemize} +\item \tcode{extent == dynamic_extent || N == extent} is \tcode{true}, and +\item \tcode{is_convertible_v} is \tcode{true}. +\begin{note} +The intent is to allow only qualification conversions +of the array element type to \tcode{element_type}. +\end{note} +\end{itemize} - template - flat_multiset(from_range_t, R&&, Allocator) - -> flat_multiset, less>, - vector, - @\exposid{alloc-rebind}@>>>; +\pnum +\effects +Constructs a \tcode{span} that is a view over the supplied array. +\begin{note} +\tcode{type_identity_t} affects class template argument deduction. +\end{note} - template> - flat_multiset(initializer_list, Compare = Compare()) - -> flat_multiset; +\pnum +\ensures +\tcode{size() == N \&\& data() == std::data(arr)} is \tcode{true}. +\end{itemdescr} - template> - flat_multiset(sorted_equivalent_t, initializer_list, Compare = Compare()) - -> flat_multiset; +\indexlibraryctor{span}% +\begin{itemdecl} +template constexpr explicit(extent != dynamic_extent) span(R&& r); +\end{itemdecl} - template - struct uses_allocator, Allocator> - : bool_constant> { }; -} -\end{codeblock} +\begin{itemdescr} +\pnum +\constraints +Let \tcode{U} be \tcode{remove_reference_t>}. +\begin{itemize} +\item \tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}} and + \tcode{ranges::\libconcept{sized_range}}. +\item Either \tcode{R} satisfies \tcode{ranges::\libconcept{borrowed_range}} or +\tcode{is_const_v} is \tcode{true}. +\item \tcode{remove_cvref_t} is not a specialization of \tcode{span}. +\item \tcode{remove_cvref_t} is not a specialization of \tcode{array}. +\item \tcode{is_array_v>} is \tcode{false}. +\item +\tcode{is_convertible_v} is \tcode{true}. +\begin{note} +The intent is to allow only qualification conversions +of the range reference type to \tcode{element_type}. +\end{note} +\end{itemize} -\rSec3[flat.multiset.cons]{Constructors} +\pnum +\expects +\begin{itemize} +\item \tcode{R} models \tcode{ranges::\libconcept{contiguous_range}} and +\tcode{ranges::\libconcept{sized_range}}. +\item If \tcode{is_const_v} is \tcode{false}, +\tcode{R} models \tcode{ranges::\libconcept{borrowed_range}}. +\end{itemize} -\indexlibraryctor{flat_multiset}% -\begin{itemdecl} -explicit flat_multiset(container_type cont, const key_compare& comp = key_compare()); -\end{itemdecl} +\pnum +\hardexpects +If \tcode{extent} is not equal to \tcode{dynamic_extent}, +then \tcode{ranges::size(r) == extent} is \tcode{true}. -\begin{itemdescr} \pnum \effects -Initializes \exposid{c} with \tcode{std::move(cont)} and -\exposid{compare} with \tcode{comp}, and -sorts the range \range{begin()}{end()} with respect to \exposid{compare}. +Initializes \exposid{data_} with \tcode{ranges::data(r)} and +\exposid{size_} with \tcode{ranges::size(r)}. \pnum -\complexity -Linear in $N$ if \tcode{cont} is sorted with respect to \exposid{compare} and -otherwise $N \log N$, where $N$ is the value of \tcode{cont.size()} before this call. +\throws +What and when \tcode{ranges::data(r)} and \tcode{ranges::size(r)} throw. \end{itemdescr} -\indexlibraryctor{flat_multiset}% +\indexlibraryctor{span}% \begin{itemdecl} -template - flat_multiset(const container_type& cont, const Allocator& a); -template - flat_multiset(const container_type& cont, const key_compare& comp, const Allocator& a); +constexpr explicit(extent != dynamic_extent) span(std::initializer_list il); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{uses_allocator_v} is \tcode{true}. +\tcode{is_const_v} is \tcode{true}. + +\pnum +\hardexpects +If \tcode{extent} is not equal to \tcode{dynamic_extent}, +then \tcode{il.size() == extent} is \tcode{true}. \pnum \effects -Equivalent to \tcode{flat_multiset(cont)} and -\tcode{flat_multiset(cont, comp)}, respectively, -except that \exposid{c} is constructed with -uses-allocator construction\iref{allocator.uses.construction}. +Initializes \exposid{data_} with \tcode{il.begin()} and +\exposid{size_} with \tcode{il.size()}. +\end{itemdescr} + +\indexlibraryctor{span}% +\begin{itemdecl} +constexpr span(const span& other) noexcept = default; +\end{itemdecl} +\begin{itemdescr} \pnum -\complexity -Same as \tcode{flat_multiset(cont)} and -\tcode{flat_multiset(cont, comp)}, respectively. +\ensures +\tcode{other.size() == size() \&\& other.data() == data()}. \end{itemdescr} -\indexlibraryctor{flat_multiset}% +\indexlibraryctor{span}% \begin{itemdecl} -template - flat_multiset(sorted_equivalent_t s, const container_type& cont, const Allocator& a); -template - flat_multiset(sorted_equivalent_t s, const container_type& cont, - const key_compare& comp, const Allocator& a); +template + constexpr explicit(@\seebelow@) span(const span& s) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{uses_allocator_v} is \tcode{true}. +\begin{itemize} +\item \tcode{extent == dynamic_extent} \tcode{||} \tcode{OtherExtent == dynamic_extent} \tcode{||} \tcode{extent == OtherExtent} is \tcode{true}, and +\item \tcode{is_convertible_v} is \tcode{true}. +\begin{note} +The intent is to allow only qualification conversions +of the \tcode{OtherElementType} to \tcode{element_type}. +\end{note} +\end{itemize} + +\pnum +\hardexpects +If \tcode{extent} is not equal to \tcode{dynamic_extent}, +then \tcode{s.size() == extent} is \tcode{true}. \pnum \effects -Equivalent to \tcode{flat_multiset(s, cont)} and -\tcode{flat_multiset(s, cont, comp)}, respectively, -except that \exposid{c} is constructed with -uses-allocator construction\iref{allocator.uses.construction}. +Constructs a \tcode{span} that is a view over the range +\range{s.data()}{s.data() + s.size()}. \pnum -\complexity -Linear. +\ensures +\tcode{size() == s.size() \&\& data() == s.data()}. + +\pnum +\remarks +The expression inside \keyword{explicit} is equivalent to: +\begin{codeblock} +extent != dynamic_extent && OtherExtent == dynamic_extent +\end{codeblock} \end{itemdescr} -\indexlibraryctor{flat_multiset}% +\indexlibrarymember{operator=}{span}% \begin{itemdecl} -template - flat_multiset(const flat_multiset&, const Allocator& a); -template - flat_multiset(flat_multiset&&, const Allocator& a); -template - flat_multiset(const key_compare& comp, const Allocator& a); -template - explicit flat_multiset(const Allocator& a); -template - flat_multiset(InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); -template - flat_multiset(InputIterator first, InputIterator last, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multiset(from_range_t, R&& rg, const Allocator& a); -template<@\exposconcept{container-compatible-range}@ R, class Allocator> - flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); -template - flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, - const key_compare& comp, const Allocator& a); -template - flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, const Allocator& a); -template - flat_multiset(initializer_list il, const key_compare& comp, const Allocator& a); -template - flat_multiset(initializer_list il, const Allocator& a); -template - flat_multiset(sorted_equivalent_t, initializer_list il, - const key_compare& comp, const Allocator& a); -template - flat_multiset(sorted_equivalent_t, initializer_list il, const Allocator& a); +constexpr span& operator=(const span& other) noexcept = default; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{uses_allocator_v} is \tcode{true}. - -\pnum -\effects -Equivalent to the corresponding non-allocator constructors -except that \exposid{c} is constructed with -uses-allocator construction\iref{allocator.uses.construction}. +\ensures +\tcode{size() == other.size() \&\& data() == other.data()}. \end{itemdescr} -\rSec3[flat.multiset.modifiers]{Modifiers} +\rSec4[span.deduct]{Deduction guides} -\indexlibrarymember{emplace}{flat_multiset}% +\indexlibrary{\idxcode{span}!deduction guide}% \begin{itemdecl} -template iterator emplace(Args&&... args); +template + span(It, EndOrSize) -> span>, + @\exposconcept{maybe-static-ext}@>; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_constructible_v} is \tcode{true}. +\tcode{It} satisfies \libconcept{contiguous_iterator}. +\end{itemdescr} -\pnum -\effects -First, initializes an object \tcode{t} of type \tcode{value_type} -with \tcode{std::forward(args)...}, -then inserts \tcode{t} as if by: -\begin{codeblock} -auto it = ranges::upper_bound(c, t, compare); -c.insert(it, std::move(t)); -\end{codeblock} +\indexlibrary{\idxcode{span}!deduction guide}% +\begin{itemdecl} +template + span(R&&) -> span>>; +\end{itemdecl} +\begin{itemdescr} \pnum -\returns -An iterator that points to the inserted element. +\constraints +\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. \end{itemdescr} -\indexlibrarymember{insert}{flat_multiset}% +\rSec4[span.sub]{Subviews} + +\indexlibrarymember{span}{first}% \begin{itemdecl} -template - void insert(InputIterator first, InputIterator last); +template constexpr span first() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Adds elements to \exposid{c} as if by: -\begin{codeblock} -c.insert(c.end(), first, last); -\end{codeblock} -Then, sorts the range of newly inserted elements with respect to \exposid{compare}, -and merges the resulting sorted range and -the sorted range of pre-existing elements into a single sorted range. +\mandates +\tcode{Count <= Extent} is \tcode{true}. \pnum -\complexity -$N$ + $M \log M$, where $N$ is \tcode{size()} before the operation and $M$ -is \tcode{distance(first, last)}. +\hardexpects +\tcode{Count <= size()} is \tcode{true}. \pnum -\remarks -Since this operation performs an in-place merge, it may allocate memory. +\effects +Equivalent to: \tcode{return R\{data(), Count\};} +where \tcode{R} is the return type. \end{itemdescr} -\indexlibrarymember{insert}{flat_multiset}% +\indexlibrarymember{span}{last}% \begin{itemdecl} -template - void insert(sorted_equivalent_t, InputIterator first, InputIterator last); +template constexpr span last() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{insert(first, last)}. +\mandates +\tcode{Count <= Extent} is \tcode{true}. \pnum -\complexity -Linear. +\hardexpects +\tcode{Count <= size()} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return R\{data() + (size() - Count), Count\};} +where \tcode{R} is the return type. \end{itemdescr} -\indexlibrarymember{swap}{flat_multiset}% +\indexlibrarymember{span}{subspan}% \begin{itemdecl} -void swap(flat_multiset& y) noexcept; +template + constexpr span subspan() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: +\mandates \begin{codeblock} -ranges::swap(compare, y.compare); -ranges::swap(c, y.c); +Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset) \end{codeblock} -\end{itemdescr} +is \tcode{true}. -\indexlibrarymember{extract}{flat_multiset}% -\begin{itemdecl} -container_type extract() &&; -\end{itemdecl} +\pnum +\hardexpects +\begin{codeblock} +Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset) +\end{codeblock} +is \tcode{true}. -\begin{itemdescr} \pnum -\ensures -\tcode{*this} is emptied, even if the function exits via an exception. +\effects +Equivalent to: +\begin{codeblock} +return span( + data() + Offset, Count != dynamic_extent ? Count : size() - Offset); +\end{codeblock} \pnum -\returns -\tcode{std::move(c)}. +\remarks +The second template argument of the returned \tcode{span} type is: +\begin{codeblock} +Count != dynamic_extent ? Count + : (Extent != dynamic_extent ? Extent - Offset + : dynamic_extent) +\end{codeblock} \end{itemdescr} -\indexlibrarymember{replace}{flat_multiset}% +\indexlibrarymember{span}{first}% \begin{itemdecl} -void replace(container_type&& cont); +constexpr span first(size_type count) const; \end{itemdecl} \begin{itemdescr} \pnum -\expects -The elements of \tcode{cont} are sorted with respect to \exposid{compare}. +\hardexpects +\tcode{count <= size()} is \tcode{true}. \pnum \effects -Equivalent to: \tcode{c = std::move(cont);} +Equivalent to: \tcode{return \{data(), count\};} \end{itemdescr} -\rSec3[flat.multiset.erasure]{Erasure} - -\indexlibrarymember{erase_if}{flat_multiset}% +\indexlibrarymember{span}{last}% \begin{itemdecl} -template - typename flat_multiset::size_type - erase_if(flat_multiset& c, Predicate pred); +constexpr span last(size_type count) const; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{Key} meets the \oldconcept{MoveAssignable} requirements. +\hardexpects +\tcode{count <= size()} is \tcode{true}. \pnum \effects -Let $E$ be \tcode{bool(pred(as_const(e)))}. -Erases all elements \tcode{e} in \tcode{c} for which $E$ holds. - -\pnum -\returns -The number of elements erased. - -\pnum -\complexity -Exactly \tcode{c.size()} applications of the predicate. - -\pnum -\remarks -Stable\iref{algorithm.stable}. -If an invocation of \tcode{erase_if} exits via an exception, -\tcode{c} is in a valid but unspecified state\iref{defns.valid}. -\begin{note} -\tcode{c} still meets its invariants, but can be empty. -\end{note} +Equivalent to: \tcode{return \{data() + (size() - count), count\};} \end{itemdescr} -\rSec2[container.adaptors.format]{Container adaptors formatting} - -\pnum -For each of -\tcode{queue}, -\tcode{priority_queue}, and -\tcode{stack}, -the library provides the following formatter specialization -where \tcode{\placeholder{adaptor-type}} is the name of the template: - -\indexlibraryglobal{formatter}% -\begin{codeblock} -namespace std { - template Container, class... U> - struct formatter<@\placeholder{adaptor-type}@, charT> { - private: - using @\exposid{maybe-const-container}@ = // \expos - @\exposid{fmt-maybe-const}@; - using @\exposid{maybe-const-adaptor}@ = // \expos - @\exposid{maybe-const}@, // see \ref{ranges.syn} - @\placeholder{adaptor-type}@>; - formatter, charT> @\exposid{underlying_}@; // \expos - - public: - template - constexpr typename ParseContext::iterator - parse(ParseContext& ctx); +\indexlibrarymember{span}{subspan}% +\begin{itemdecl} +constexpr span subspan( + size_type offset, size_type count = dynamic_extent) const; +\end{itemdecl} - template - typename FormatContext::iterator - format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; - }; -} +\begin{itemdescr} +\pnum +\hardexpects +\begin{codeblock} +offset <= size() && (count == dynamic_extent || count <= size() - offset) \end{codeblock} +is \tcode{true}. -\indexlibrarymember{parse}{formatter}% +\pnum +\effects +Equivalent to: +\begin{codeblock} +return {data() + offset, count == dynamic_extent ? size() - offset : count}; +\end{codeblock} +\end{itemdescr} + +\rSec4[span.obs]{Observers} + +\indexlibrarymember{span}{size}% \begin{itemdecl} -template - constexpr typename ParseContext::iterator - parse(ParseContext& ctx); +constexpr size_type size() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +Equivalent to: \tcode{return \exposid{size_};} \end{itemdescr} -\indexlibrarymember{format}{formatter}% +\indexlibrarymember{span}{size_bytes}% \begin{itemdecl} -template - typename FormatContext::iterator - format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; +constexpr size_type size_bytes() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{underlying_}.format(r.c, ctx);} +Equivalent to: \tcode{return size() * sizeof(element_type);} \end{itemdescr} -\rSec1[views]{Views} - -\rSec2[views.general]{General} +\indexlibrarymember{span}{empty}% +\begin{itemdecl} +constexpr bool empty() const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -The header \libheader{span} defines the view \tcode{span}. -The header \libheader{mdspan} defines the class template \tcode{mdspan} and -other facilities for interacting with these multidimensional views. +\effects +Equivalent to: \tcode{return size() == 0;} +\end{itemdescr} -\rSec2[views.contiguous]{Contiguous access} +\rSec4[span.elem]{Element access} -\rSec3[span.syn]{Header \tcode{} synopsis}% +\indexlibrary{\idxcode{operator[]}!\idxcode{span}}% +\begin{itemdecl} +constexpr reference operator[](size_type idx) const; +\end{itemdecl} -\indexheader{span}% -\begin{codeblock} -namespace std { - // constants - inline constexpr size_t @\libglobal{dynamic_extent}@ = numeric_limits::max(); +\begin{itemdescr} +\pnum +\hardexpects +\tcode{idx < size()} is \tcode{true}. - // \ref{views.span}, class template \tcode{span} - template - class span; +\pnum +\returns +\tcode{*(data() + idx)}. - template - constexpr bool ranges::@\libspec{enable_view}{span}@> = true; - template - constexpr bool ranges::@\libspec{enable_borrowed_range}{span}@> = true; +\pnum +\throws +Nothing. +\end{itemdescr} - // \ref{span.objectrep}, views of object representation - template - span - as_bytes(span s) noexcept; +\indexlibrarymember{span}{at}% +\begin{itemdecl} +constexpr reference at(size_type idx) const; +\end{itemdecl} - template - span - as_writable_bytes(span s) noexcept; -} -\end{codeblock} +\begin{itemdescr} +\pnum +\returns +\tcode{*(data() + idx)}. -\rSec3[views.span]{Class template \tcode{span}} +\pnum +\throws +\tcode{out_of_range} if \tcode{idx >= size()} is \tcode{true}. +\end{itemdescr} -\rSec4[span.overview]{Overview} +\indexlibrarymember{span}{front}% +\begin{itemdecl} +constexpr reference front() const; +\end{itemdecl} +\begin{itemdescr} \pnum -\indexlibraryglobal{span}% -A \tcode{span} is a view over a contiguous sequence of objects, -the storage of which is owned by some other object. +\hardexpects +\tcode{empty()} is \tcode{false}. \pnum -All member functions of \tcode{span} have constant time complexity. +\returns +\tcode{*data()}. -\indexlibraryglobal{span}% -\begin{codeblock} -namespace std { - template - class span { - public: - // constants and types - using element_type = ElementType; - using value_type = remove_cv_t; - using size_type = size_t; - using difference_type = ptrdiff_t; - using pointer = element_type*; - using const_pointer = const element_type*; - using reference = element_type&; - using const_reference = const element_type&; - using iterator = @\impdefx{type of \tcode{span::iterator}}@; // see \ref{span.iterators} - using const_iterator = std::const_iterator; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::const_iterator; - static constexpr size_type extent = Extent; +\pnum +\throws +Nothing. +\end{itemdescr} - // \ref{span.cons}, constructors, copy, and assignment - constexpr span() noexcept; - template - constexpr explicit(extent != dynamic_extent) span(It first, size_type count); - template - constexpr explicit(extent != dynamic_extent) span(It first, End last); - template - constexpr span(type_identity_t (&arr)[N]) noexcept; - template - constexpr span(array& arr) noexcept; - template - constexpr span(const array& arr) noexcept; - template - constexpr explicit(extent != dynamic_extent) span(R&& r); - constexpr span(const span& other) noexcept = default; - template - constexpr explicit(@\seebelow@) span(const span& s) noexcept; +\indexlibrarymember{span}{back}% +\begin{itemdecl} +constexpr reference back() const; +\end{itemdecl} - constexpr span& operator=(const span& other) noexcept = default; +\begin{itemdescr} +\pnum +\hardexpects +\tcode{empty()} is \tcode{false}. - // \ref{span.sub}, subviews - template - constexpr span first() const; - template - constexpr span last() const; - template - constexpr span subspan() const; +\pnum +\returns +\tcode{*(data() + (size() - 1))}. - constexpr span first(size_type count) const; - constexpr span last(size_type count) const; - constexpr span subspan( - size_type offset, size_type count = dynamic_extent) const; +\pnum +\throws +Nothing. +\end{itemdescr} - // \ref{span.obs}, observers - constexpr size_type size() const noexcept; - constexpr size_type size_bytes() const noexcept; - [[nodiscard]] constexpr bool empty() const noexcept; +\indexlibrarymember{span}{data}% +\begin{itemdecl} +constexpr pointer data() const noexcept; +\end{itemdecl} - // \ref{span.elem}, element access - constexpr reference operator[](size_type idx) const; - constexpr reference front() const; - constexpr reference back() const; - constexpr pointer data() const noexcept; +\begin{itemdescr} +\pnum +\returns +\exposid{data_}. +\end{itemdescr} - // \ref{span.iterators}, iterator support - constexpr iterator begin() const noexcept; - constexpr iterator end() const noexcept; - constexpr const_iterator cbegin() const noexcept { return begin(); } - constexpr const_iterator cend() const noexcept { return end(); } - constexpr reverse_iterator rbegin() const noexcept; - constexpr reverse_iterator rend() const noexcept; - constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } - constexpr const_reverse_iterator crend() const noexcept { return rend(); } +\rSec4[span.iterators]{Iterator support} - private: - pointer @\exposid{data_}@; // \expos - size_type @\exposid{size_}@; // \expos - }; +\indexlibrarymember{iterator}{span}% +\begin{itemdecl} +using iterator = @\impdefx{type of \tcode{span::iterator}}@; +\end{itemdecl} - template - span(It, EndOrSize) -> span>>; - template - span(T (&)[N]) -> span; - template - span(array&) -> span; - template - span(const array&) -> span; - template - span(R&&) -> span>>; -} -\end{codeblock} +\begin{itemdescr} +\pnum +The type +models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, +meets the \oldconcept{RandomAccessIterator} +requirements\iref{random.access.iterators}, +and +meets the requirements for +constexpr iterators\iref{iterator.requirements.general}, +whose value type is \tcode{value_type} and +whose reference type is \tcode{reference}. \pnum -\tcode{span} is -a trivially copyable type\iref{term.trivially.copyable.type}. +All requirements on container iterators\iref{container.reqmts} apply to +\tcode{span::iterator} as well. +\end{itemdescr} +\indexlibrarymember{span}{begin}% +\begin{itemdecl} +constexpr iterator begin() const noexcept; +\end{itemdecl} + +\begin{itemdescr} \pnum -\tcode{ElementType} is required to be -a complete object type that is not an abstract class type. +\returns +An iterator referring to the first element in the span. +If \tcode{empty()} is \tcode{true}, then it returns the +same value as \tcode{end()}. +\end{itemdescr} -\rSec4[span.cons]{Constructors, copy, and assignment} +\indexlibrarymember{span}{end}% +\begin{itemdecl} +constexpr iterator end() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An iterator which is the past-the-end value. +\end{itemdescr} -\indexlibraryctor{span}% +\indexlibrarymember{span}{rbegin}% \begin{itemdecl} -constexpr span() noexcept; +constexpr reverse_iterator rbegin() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{Extent == dynamic_extent || Extent == 0} is \tcode{true}. - -\pnum -\ensures -\tcode{size() == 0 \&\& data() == nullptr}. +\effects +Equivalent to: \tcode{return reverse_iterator(end());} \end{itemdescr} -\indexlibraryctor{span}% +\indexlibrarymember{span}{rend}% \begin{itemdecl} -template - constexpr explicit(extent != dynamic_extent) span(It first, size_type count); +constexpr reverse_iterator rend() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -Let \tcode{U} be \tcode{remove_reference_t>}. -\begin{itemize} -\item \tcode{It} satisfies \libconcept{contiguous_iterator}. -\item -\tcode{is_convertible_v} is \tcode{true}. -\begin{note} -The intent is to allow only qualification conversions -of the iterator reference type to \tcode{element_type}. -\end{note} -\end{itemize} +\effects +Equivalent to: \tcode{return reverse_iterator(begin());} +\end{itemdescr} -\pnum -\expects -\begin{itemize} -\item \range{first}{first + count} is a valid range. -\item \tcode{It} models \libconcept{contiguous_iterator}. -\item -If \tcode{extent} is not equal to \tcode{dynamic_extent}, -then \tcode{count} is equal to \tcode{extent}. -\end{itemize} +\rSec3[span.objectrep]{Views of object representation} -\pnum -\effects -Initializes \exposid{data_} with \tcode{to_address(first)} and -\exposid{size_} with \tcode{count}. +\indexlibraryglobal{as_bytes}% +\begin{itemdecl} +template + span + as_bytes(span s) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\throws -Nothing. +\effects +Equivalent to: \tcode{return R\{reinterpret_cast(s.data()), s.size_bytes()\};} +where \tcode{R} is the return type. \end{itemdescr} -\indexlibraryctor{span}% +\indexlibraryglobal{as_writable_bytes}% \begin{itemdecl} -template - constexpr explicit(extent != dynamic_extent) span(It first, End last); +template + span + as_writable_bytes(span s) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -Let \tcode{U} be \tcode{remove_reference_t>}. -\begin{itemize} -\item -\tcode{is_convertible_v} is \tcode{true}. -\begin{note} -The intent is to allow only qualification conversions -of the iterator reference type to \tcode{element_type}. -\end{note} -\item \tcode{It} satisfies \libconcept{contiguous_iterator}. -\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. -\item \tcode{is_convertible_v} is \tcode{false}. -\end{itemize} - -\pnum -\expects -\begin{itemize} -\item -If \tcode{extent} is not equal to \tcode{dynamic_extent}, -then \tcode{last - first} is equal to \tcode{extent}. -\item \range{first}{last} is a valid range. -\item \tcode{It} models \libconcept{contiguous_iterator}. -\item \tcode{End} models \tcode{\libconcept{sized_sentinel_for}}. -\end{itemize} +\tcode{is_const_v} is \tcode{false}. \pnum \effects -Initializes \exposid{data_} with \tcode{to_address(first)} and -\exposid{size_} with \tcode{last - first}. +Equivalent to: \tcode{return R\{reinterpret_cast(s.data()), s.size_bytes()\};} +where \tcode{R} is the return type. +\end{itemdescr} + +\rSec2[views.multidim]{Multidimensional access} + +\rSec3[mdspan.overview]{Overview} \pnum -\throws -When and what \tcode{last - first} throws. -\end{itemdescr} +A \defnadj{multidimensional}{index space} is +a Cartesian product of integer intervals. +Each interval can be represented by a half-open range $[L_i, U_i)$, +where $L_i$ and $U_i$ are the lower and upper bounds of +the $i^\text{th}$ dimension. +The \defn{rank} of a multidimensional index space is +the number of intervals it represents. +The \defn{size of a multidimensional index space} is +the product of $U_i - L_i$ for each dimension $i$ +if its rank is greater than 0, and 1 otherwise. -\indexlibraryctor{span}% -\begin{itemdecl} -template constexpr span(type_identity_t (&arr)[N]) noexcept; -template constexpr span(array& arr) noexcept; -template constexpr span(const array& arr) noexcept; -\end{itemdecl} +\pnum +An integer $r$ is a \defn{rank index} of an index space $S$ +if $r$ is in the range $[0, \text{rank of $S$})$. -\begin{itemdescr} \pnum -\constraints -Let \tcode{U} be \tcode{remove_pointer_t}. +A pack of integers \tcode{idx} is +a \defnadj{multidimensional}{index} in a multidimensional index space $S$ +(or representation thereof) if both of the following are true: \begin{itemize} -\item \tcode{extent == dynamic_extent || N == extent} is \tcode{true}, and -\item \tcode{is_convertible_v} is \tcode{true}. -\begin{note} -The intent is to allow only qualification conversions -of the array element type to \tcode{element_type}. -\end{note} +\item +\tcode{sizeof...(idx)} is equal to the rank of $S$, and +\item +for every rank index $i$ of $S$, +the $i^\text{th}$ value of \tcode{idx} is an integer +in the interval $[L_i, U_i)$ of $S$. \end{itemize} -\pnum -\effects -Constructs a \tcode{span} that is a view over the supplied array. -\begin{note} -\tcode{type_identity_t} affects class template argument deduction. -\end{note} +\rSec3[mdspan.syn]{Header \tcode{} synopsis} -\pnum -\ensures -\tcode{size() == N \&\& data() == std::data(arr)} is \tcode{true}. -\end{itemdescr} +\indexheader{mdspan}% +\begin{codeblock} +// all freestanding +namespace std { + // \ref{mdspan.extents}, class template \tcode{extents} + template + class extents; -\indexlibraryctor{span}% -\begin{itemdecl} -template constexpr explicit(extent != dynamic_extent) span(R&& r); -\end{itemdecl} + // \ref{mdspan.extents.dextents}, alias template \tcode{dextents} + template + using dextents = @\seebelow@; + + // \ref{mdspan.extents.dims}, alias template \tcode{dims} + template + using dims = @\seebelow@; + + // \ref{mdspan.layout}, layout mapping + struct layout_left; + struct layout_right; + struct layout_stride; + template + struct layout_left_padded; + template + struct layout_right_padded; + + // \ref{mdspan.accessor.default}, class template \tcode{default_accessor} + template + class default_accessor; + + // \ref{mdspan.accessor.aligned}, class template \tcode{aligned_accessor} + template + class aligned_accessor; + + // \ref{mdspan.mdspan}, class template \tcode{mdspan} + template> + class mdspan; + + // \ref{mdspan.sub}, \tcode{submdspan} creation + template + struct strided_slice; + + template + struct submdspan_mapping_result; + + struct full_extent_t { explicit full_extent_t() = default; }; + inline constexpr full_extent_t full_extent{}; + + template + constexpr auto submdspan_extents(const extents&, SliceSpecifiers...); + + // \ref{mdspan.sub.sub}, \tcode{submdspan} function template + template + constexpr auto submdspan( + const mdspan& src, + SliceSpecifiers... slices) -> @\seebelow@; + + template + concept @\defexposconcept{index-pair-like}@ = // \expos + @\exposconcept{pair-like}@ && + @\libconcept{convertible_to}@, IndexType> && + @\libconcept{convertible_to}@, IndexType>; +} +\end{codeblock} + +\rSec3[mdspan.extents]{Class template \tcode{extents}} + +\rSec4[mdspan.extents.overview]{Overview} + +The class template \tcode{extents} represents +a multidimensional index space of rank equal to \tcode{sizeof...(Extents)}. +In \iref{views}, +\tcode{extents} is used synonymously with multidimensional index space. + +\begin{codeblock} +namespace std { + template + class @\libglobal{extents}@ { + public: + using index_type = IndexType; + using size_type = make_unsigned_t; + using rank_type = size_t; + + // \ref{mdspan.extents.obs}, observers of the multidimensional index space + static constexpr rank_type rank() noexcept { return sizeof...(Extents); } + static constexpr rank_type rank_dynamic() noexcept { return @\exposid{dynamic-index}@(rank()); } + static constexpr size_t static_extent(rank_type) noexcept; + constexpr index_type extent(rank_type) const noexcept; + + // \ref{mdspan.extents.cons}, constructors + constexpr extents() noexcept = default; + + template + constexpr explicit(@\seebelow@) + extents(const extents&) noexcept; + template + constexpr explicit extents(OtherIndexTypes...) noexcept; + template + constexpr explicit(N != rank_dynamic()) + extents(span) noexcept; + template + constexpr explicit(N != rank_dynamic()) + extents(const array&) noexcept; + + // \ref{mdspan.extents.cmp}, comparison operators + template + friend constexpr bool operator==(const extents&, + const extents&) noexcept; + + // \ref{mdspan.extents.expo}, exposition-only helpers + constexpr size_t @\exposid{fwd-prod-of-extents}@(rank_type) const noexcept; // \expos + constexpr size_t @\exposid{rev-prod-of-extents}@(rank_type) const noexcept; // \expos + template + static constexpr auto @\exposid{index-cast}@(OtherIndexType&&) noexcept; // \expos + + private: + static constexpr rank_type @\exposid{dynamic-index}@(rank_type) noexcept; // \expos + static constexpr rank_type @\exposid{dynamic-index-inv}@(rank_type) noexcept; // \expos + array @\exposid{dynamic-extents}@{}; // \expos + }; + + template + explicit extents(Integrals...) + -> @\seebelow@; +} +\end{codeblock} -\begin{itemdescr} \pnum -\constraints -Let \tcode{U} be \tcode{remove_reference_t>}. +\mandates \begin{itemize} -\item \tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}} and - \tcode{ranges::\libconcept{sized_range}}. -\item Either \tcode{R} satisfies \tcode{ranges::\libconcept{borrowed_range}} or -\tcode{is_const_v} is \tcode{true}. -\item \tcode{remove_cvref_t} is not a specialization of \tcode{span}. -\item \tcode{remove_cvref_t} is not a specialization of \tcode{array}. -\item \tcode{is_array_v>} is \tcode{false}. \item -\tcode{is_convertible_v} is \tcode{true}. -\begin{note} -The intent is to allow only qualification conversions -of the range reference type to \tcode{element_type}. -\end{note} +\tcode{IndexType} is a signed or unsigned integer type, and +\item +each element of \tcode{Extents} is either equal to \tcode{dynamic_extent}, or +is representable as a value of type \tcode{IndexType}. \end{itemize} \pnum -\expects -\begin{itemize} -\item If \tcode{extent} is not equal to \tcode{dynamic_extent}, -then \tcode{ranges::size(r)} is equal to \tcode{extent}. -\item \tcode{R} models \tcode{ranges::\libconcept{contiguous_range}} and -\tcode{ranges::\libconcept{sized_range}}. -\item If \tcode{is_const_v} is \tcode{false}, -\tcode{R} models \tcode{ranges::\libconcept{borrowed_range}}. -\end{itemize} +Each specialization of \tcode{extents} models \libconcept{regular} and +is trivially copyable. \pnum -\effects -Initializes \exposid{data_} with \tcode{ranges::data(r)} and -\exposid{size_} with \tcode{ranges::size(r)}. +Let $E_r$ be the $r^\text{th}$ element of \tcode{Extents}. +$E_r$ is a \defnadj{dynamic}{extent} if it is equal to \tcode{dynamic_extent}, +otherwise $E_r$ is a \defnadj{static}{extent}. +Let $D_r$ be the value of \tcode{\exposid{dynamic-extents}[\exposid{dynamic-index}($r$)]} +if $E_r$ is a dynamic extent, +otherwise $E_r$. \pnum -\throws -What and when \tcode{ranges::data(r)} and \tcode{ranges::size(r)} throw. -\end{itemdescr} +The $r^\text{th}$ interval of the multidimensional index space +represented by an \tcode{extents} object is $[0, D_r)$. + +\rSec4[mdspan.extents.expo]{Exposition-only helpers} -\indexlibraryctor{span}% \begin{itemdecl} -constexpr span(const span& other) noexcept = default; +static constexpr rank_type @\exposid{dynamic-index}@(rank_type i) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\ensures -\tcode{other.size() == size() \&\& other.data() == data()}. +\expects +\tcode{i <= rank()} is \tcode{true}. + +\pnum +\returns +The number of $E_r$ with $r < \tcode{i}$ for which $E_r$ is a dynamic extent. \end{itemdescr} -\indexlibraryctor{span}% \begin{itemdecl} -template - constexpr explicit(@\seebelow@) span(const span& s) noexcept; +static constexpr rank_type @\exposid{dynamic-index-inv}@(rank_type i) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item \tcode{extent == dynamic_extent} \tcode{||} \tcode{OtherExtent == dynamic_extent} \tcode{||} \tcode{extent == OtherExtent} is \tcode{true}, and -\item \tcode{is_convertible_v} is \tcode{true}. -\begin{note} -The intent is to allow only qualification conversions -of the \tcode{OtherElementType} to \tcode{element_type}. -\end{note} -\end{itemize} - \pnum \expects -If \tcode{extent} is not equal to \tcode{dynamic_extent}, -then \tcode{s.size()} is equal to \tcode{extent}. - -\pnum -\effects -Constructs a \tcode{span} that is a view over the range -\range{s.data()}{s.data() + s.size()}. - -\pnum -\ensures -\tcode{size() == s.size() \&\& data() == s.data()}. +\tcode{i < rank_dynamic()} is \tcode{true}. \pnum -\remarks -The expression inside \keyword{explicit} is equivalent to: -\begin{codeblock} -extent != dynamic_extent && OtherExtent == dynamic_extent -\end{codeblock} +\returns +The minimum value of $r$ +such that \tcode{\exposid{dynamic-index}($r$ + 1) == i + 1} is \tcode{true}. \end{itemdescr} -\indexlibrarymember{operator=}{span}% \begin{itemdecl} -constexpr span& operator=(const span& other) noexcept = default; +constexpr size_t @\exposid{fwd-prod-of-extents}@(rank_type i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\ensures -\tcode{size() == other.size() \&\& data() == other.data()}. -\end{itemdescr} - -\rSec4[span.deduct]{Deduction guides} - -\indexlibrary{\idxcode{span}!deduction guide}% -\begin{itemdecl} -template - span(It, EndOrSize) -> span>>; -\end{itemdecl} +\expects +\tcode{i <= rank()} is \tcode{true}. -\begin{itemdescr} \pnum -\constraints -\tcode{It} satisfies \libconcept{contiguous_iterator}. +\returns +If \tcode{i > 0} is \tcode{true}, +the product of \tcode{extent($k$)} for all $k$ in the range $[0, \tcode{i})$, +otherwise \tcode{1}. \end{itemdescr} -\indexlibrary{\idxcode{span}!deduction guide}% \begin{itemdecl} -template - span(R&&) -> span>>; +constexpr size_t @\exposid{rev-prod-of-extents}@(rank_type i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. -\end{itemdescr} +\expects +\tcode{i < rank()} is \tcode{true}. -\rSec4[span.sub]{Subviews} +\pnum +\returns +If \tcode{i + 1 < rank()} is \tcode{true}, +the product of \tcode{extent($k$)} +for all $k$ in the range $[\tcode{i + 1}, \tcode{rank()})$, +otherwise \tcode{1}. +\end{itemdescr} -\indexlibrarymember{span}{first}% \begin{itemdecl} -template constexpr span first() const; +template + static constexpr auto @\exposid{index-cast}@(OtherIndexType&& i) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\mandates -\tcode{Count <= Extent} is \tcode{true}. - -\pnum -\expects -\tcode{Count <= size()} is \tcode{true}. - \pnum \effects -Equivalent to: \tcode{return R\{data(), Count\};} -where \tcode{R} is the return type. +\begin{itemize} +\item +If \tcode{OtherIndexType} is an integral type other than \tcode{bool}, +then equivalent to \tcode{return i;}, +\item +otherwise, equivalent to \tcode{return static_cast(i);}. +\end{itemize} +\begin{note} +This function will always return an integral type other than \tcode{bool}. +Since this function's call sites are constrained on +convertibility of \tcode{OtherIndexType} to \tcode{index_type}, +integer-class types can use the \tcode{static_cast} branch +without loss of precision. +\end{note} \end{itemdescr} -\indexlibrarymember{span}{last}% +\rSec4[mdspan.extents.cons]{Constructors} + +\indexlibraryctor{extents}% \begin{itemdecl} -template constexpr span last() const; +template + constexpr explicit(@\seebelow@) + extents(const extents& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\mandates -\tcode{Count <= Extent} is \tcode{true}. +\constraints +\begin{itemize} +\item +\tcode{sizeof...(OtherExtents) == rank()} is \tcode{true}. +\item +\tcode{((OtherExtents == dynamic_extent || Extents == dynamic_extent || OtherExtents ==\newline Extents) \&\& ...)} is \tcode{true}. +\end{itemize} \pnum \expects -\tcode{Count <= size()} is \tcode{true}. +\begin{itemize} +\item +\tcode{other.extent($r$)} equals $E_r$ +for each $r$ for which $E_r$ is a static extent, and +\item +either +\begin{itemize} +\item +\tcode{sizeof...(OtherExtents)} is zero, or +\item +\tcode{other.extent($r$)} is representable as +a value of type \tcode{index_type} for every rank index $r$ of \tcode{other}. +\end{itemize} +\end{itemize} \pnum -\effects -Equivalent to: \tcode{return R\{data() + (size() - Count), Count\};} -where \tcode{R} is the return type. +\ensures +\tcode{*this == other} is \tcode{true}. + +\pnum +\remarks +The expression inside \tcode{explicit} is equivalent to: +\begin{codeblock} +(((Extents != dynamic_extent) && (OtherExtents == dynamic_extent)) || ... ) || +(numeric_limits::max() < numeric_limits::max()) +\end{codeblock} \end{itemdescr} -\indexlibrarymember{span}{subspan}% +\indexlibraryctor{extents}% \begin{itemdecl} -template - constexpr span subspan() const; +template + constexpr explicit extents(OtherIndexTypes... exts) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\mandates -\begin{codeblock} -Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset) -\end{codeblock} -is \tcode{true}. +Let \tcode{N} be \tcode{sizeof...(OtherIndexTypes)}, +and let \tcode{exts_arr} be +\tcode{array\{static_cast<\\index_type>(std::move(exts))...\}}. \pnum -\expects -\begin{codeblock} -Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset) -\end{codeblock} -is \tcode{true}. +\constraints +\begin{itemize} +\item +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, +\item +\tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}, and +\item +\tcode{N == rank_dynamic() || N == rank()} is \tcode{true}. +\begin{note} +One can construct \tcode{extents} from just dynamic extents, +which are all the values getting stored, or +from all the extents with a precondition. +\end{note} +\end{itemize} \pnum -\effects -Equivalent to: -\begin{codeblock} -return span( - data() + Offset, Count != dynamic_extent ? Count : size() - Offset); -\end{codeblock} +\expects +\begin{itemize} +\item +If \tcode{N != rank_dynamic()} is \tcode{true}, +\tcode{exts_arr[$r$]} equals $E_r$ +for each $r$ for which $E_r$ is a static extent, and +\item +either +\begin{itemize} +\item +\tcode{sizeof...(exts) == 0} is \tcode{true}, or +\item +each element of \tcode{exts} is representable +as a nonnegative value of type \tcode{index_type}. +\end{itemize} +\end{itemize} \pnum -\remarks -The second template argument of the returned \tcode{span} type is: -\begin{codeblock} -Count != dynamic_extent ? Count - : (Extent != dynamic_extent ? Extent - Offset - : dynamic_extent) -\end{codeblock} +\ensures +\tcode{*this == extents(exts_arr)} is \tcode{true}. \end{itemdescr} -\indexlibrarymember{span}{first}% +\indexlibraryctor{extents}% \begin{itemdecl} -constexpr span first(size_type count) const; +template + constexpr explicit(N != rank_dynamic()) + extents(span exts) noexcept; +template + constexpr explicit(N != rank_dynamic()) + extents(const array& exts) noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}, +\item +\tcode{is_nothrow_constructible_v} is \tcode{true}, and +\item +\tcode{N == rank_dynamic() || N == rank()} is \tcode{true}. +\end{itemize} + \pnum \expects -\tcode{count <= size()} is \tcode{true}. +\begin{itemize} +\item +If \tcode{N != rank_dynamic()} is \tcode{true}, +\tcode{exts[$r$]} equals $E_r$ for each $r$ for which $E_r$ is a static extent, and +\item +either +\begin{itemize} +\item +\tcode{N} is zero, or +\item +\tcode{exts[$r$]} is representable +as a nonnegative value of type \tcode{index_type} for every rank index $r$. +\end{itemize} +\end{itemize} \pnum \effects -Equivalent to: \tcode{return \{data(), count\};} +\begin{itemize} +\item +If \tcode{N} equals \tcode{rank_dynamic()}, +for all $d$ in the range $[0, \tcode{rank_dynamic()})$, +direct-non-list-initializes \tcode{\exposidnc{dynamic-extents}[$d$]} +with \tcode{as_const(exts[$d$])}. +\item +Otherwise, for all $d$ in the range $[0, \tcode{rank_dynamic()})$, +direct-non-list-initializes \exposidnc{dynamic-ex\-tents}\tcode{[$d$]} +with \tcode{as_const(exts[\exposidnc{dynamic-index-inv}($d$)])}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{span}{last}% +\indexlibraryctor{extents}% \begin{itemdecl} -constexpr span last(size_type count) const; +template + explicit extents(Integrals...) -> @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{count <= size()} is \tcode{true}. +\constraints +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}. \pnum -\effects -Equivalent to: \tcode{return \{data() + (size() - count), count\};} +\remarks +The deduced type is \tcode{extents...>}. \end{itemdescr} -\indexlibrarymember{span}{subspan}% +\rSec4[mdspan.extents.obs]{Observers of the multidimensional index space} + +\indexlibrarymember{static_extent}{extents}% \begin{itemdecl} -constexpr span subspan( - size_type offset, size_type count = dynamic_extent) const; +static constexpr size_t static_extent(rank_type i) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects -\begin{codeblock} -offset <= size() && (count == dynamic_extent || count <= size() - offset) -\end{codeblock} -is \tcode{true}. +\tcode{i < rank()} is \tcode{true}. \pnum -\effects -Equivalent to: -\begin{codeblock} -return {data() + offset, count == dynamic_extent ? size() - offset : count}; -\end{codeblock} +\returns +$E_\tcode{i}$. \end{itemdescr} -\rSec4[span.obs]{Observers} - -\indexlibrarymember{span}{size}% +\indexlibrarymember{extent}{extents}% \begin{itemdecl} -constexpr size_type size() const noexcept; +constexpr index_type extent(rank_type i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return \exposid{size_};} -\end{itemdescr} - -\indexlibrarymember{span}{size_bytes}% -\begin{itemdecl} -constexpr size_type size_bytes() const noexcept; -\end{itemdecl} +\expects +\tcode{i < rank()} is \tcode{true}. -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return size() * sizeof(element_type);} +\returns +$D_\tcode{i}$. \end{itemdescr} -\indexlibrarymember{span}{empty}% +\rSec4[mdspan.extents.cmp]{Comparison operators} + +\indexlibrarymember{operator==}{extents}% \begin{itemdecl} -[[nodiscard]] constexpr bool empty() const noexcept; +template + friend constexpr bool operator==(const extents& lhs, + const extents& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return size() == 0;} +\returns +\tcode{true} if \tcode{lhs.rank()} equals \tcode{rhs.rank()} and +if \tcode{lhs.extent(r)} equals \tcode{rhs.extent(r)} +for every rank index \tcode{r} of \tcode{rhs}, +otherwise \tcode{false}. \end{itemdescr} -\rSec4[span.elem]{Element access} +\rSec4[mdspan.extents.dextents]{Alias template \tcode{dextents}} -\indexlibrary{\idxcode{operator[]}!\idxcode{span}}% +\indexlibraryglobal{dextents}% \begin{itemdecl} -constexpr reference operator[](size_type idx) const; +template + using dextents = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{idx < size()} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return *(data() + idx);} +\result +A type \tcode{E} that is a specialization of \tcode{extents} +such that \tcode{E::rank() == Rank \&\& E::rank() == E::rank_dynamic()} is \tcode{true}, and +\tcode{E::index_type} denotes \tcode{IndexType}. \end{itemdescr} -\indexlibrarymember{span}{front}% +\rSec4[mdspan.extents.dims]{Alias template \tcode{dims}} + +\indexlibraryglobal{dims}% \begin{itemdecl} -constexpr reference front() const; +template + using dims = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{empty()} is \tcode{false}. - -\pnum -\effects -Equivalent to: \tcode{return *data();} +\result +A type \tcode{E} that is a specialization of \tcode{extents} +such that \tcode{E::rank() == Rank \&\& E::rank() == E::rank_dynamic()} is \tcode{true}, and +\tcode{E::index_type} denotes \tcode{IndexType}. \end{itemdescr} -\indexlibrarymember{span}{back}% -\begin{itemdecl} -constexpr reference back() const; -\end{itemdecl} +\rSec3[mdspan.layout]{Layout mapping} -\begin{itemdescr} -\pnum -\expects -\tcode{empty()} is \tcode{false}. +\rSec4[mdspan.layout.general]{General} \pnum -\effects -Equivalent to: \tcode{return *(data() + (size() - 1));} -\end{itemdescr} +In \ref{mdspan.layout.reqmts} and \ref{mdspan.layout.policy.reqmts}: -\indexlibrarymember{span}{data}% -\begin{itemdecl} -constexpr pointer data() const noexcept; -\end{itemdecl} +\begin{itemize} +\item +\tcode{M} denotes a layout mapping class. -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return \exposid{data_};} -\end{itemdescr} +\item +\tcode{m} denotes a (possibly const) value of type \tcode{M}. -\rSec4[span.iterators]{Iterator support} +\item +\tcode{i} and \tcode{j} are packs of (possibly const) integers +that are multidimensional indices in \tcode{m.extents()}\iref{mdspan.overview}. +\begin{note} +The type of each element of the packs can be a different integer type. +\end{note} -\indexlibrarymember{iterator}{span}% -\begin{itemdecl} -using iterator = @\impdefx{type of \tcode{span::iterator}}@; -\end{itemdecl} +\item +\tcode{r} is a (possibly const) rank index of \tcode{typename M::extents_type}. + +\item +$\tcode{d}_r$ is a pack of (possibly const) integers +for which \tcode{sizeof...($\tcode{d}_r$) == M::extents_type::rank()} is \tcode{true}, +the $r^\text{th}$ element is equal to 1, and +all other elements are equal to 0. +\end{itemize} -\begin{itemdescr} \pnum -The type -models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, -meets the \oldconcept{RandomAccessIterator} -requirements\iref{random.access.iterators}, -and -meets the requirements for -constexpr iterators\iref{iterator.requirements.general}, -whose value type is \tcode{value_type} and -whose reference type is \tcode{reference}. +In \ref{mdspan.layout.reqmts} through \ref{mdspan.layout.stride}: +\begin{itemize} +\item +Let \exposid{is-mapping-of} be the exposition-only variable template defined as follows: +\begin{codeblock} +template +constexpr bool @\exposid{is-mapping-of}@ = // \expos + is_same_v, Mapping>; +\end{codeblock} +\item +Let \exposid{is-layout-left-padded-mapping-of} be +the exposition-only variable template defined as follows: +\begin{codeblock} +template +constexpr bool @\exposid{is-layout-left-padded-mapping-of}@ = @\seebelow@; // \expos +\end{codeblock} +where \tcode{\exposid{is-layout-left-padded-mapping-of}} is \tcode{true} +if and only if \tcode{Mapping} denotes +a specialization of \tcode{layout_left_padded::mapping} +for some value \tcode{S} of type \tcode{size_t}. +\item +Let \exposid{is-layout-right-padded-mapping-of} be +the exposition-only variable template defined as follows: +\begin{codeblock} +template +constexpr bool @\exposid{is-layout-right-padded-mapping-of}@ = @\seebelow@; // \expos +\end{codeblock} +where \tcode{\exposid{is-layout-right-padded-mapping-of}} is \tcode{true} +if and only if \tcode{Mapping} denotes +a specialization of \tcode{layout_right_padded::mapping} +for some value \tcode{S} of type \tcode{size_t}. +\item +For nonnegative integers $x$ and $y$, +let $\exposid{LEAST-MULTIPLE-AT-LEAST}(x, y)$ denote +\begin{itemize} +\item +$y$ if $x$ is zero, +\item +otherwise, the least multiple of $x$ that is greater than or equal to $y$. +\end{itemize} +\end{itemize} + +\rSec4[mdspan.layout.reqmts]{Requirements} \pnum -All requirements on container iterators\iref{container.reqmts} apply to -\tcode{span::iterator} as well. -\end{itemdescr} +A type \tcode{M} meets the \defn{layout mapping} requirements if + +\begin{itemize} +\item +\tcode{M} models \libconcept{copyable} and \libconcept{equality_comparable}, +\item +\tcode{is_nothrow_move_constructible_v} is \tcode{true}, +\item +\tcode{is_nothrow_move_assignable_v} is \tcode{true}, +\item +\tcode{is_nothrow_swappable_v} is \tcode{true}, and +\item +the following types and expressions are well-formed and +have the specified semantics. +\end{itemize} -\indexlibrarymember{span}{begin}% \begin{itemdecl} -constexpr iterator begin() const noexcept; +typename M::extents_type \end{itemdecl} \begin{itemdescr} \pnum -\returns -An iterator referring to the first element in the span. -If \tcode{empty()} is \tcode{true}, then it returns the -same value as \tcode{end()}. +\result +A type that is a specialization of \tcode{extents}. \end{itemdescr} -\indexlibrarymember{span}{end}% \begin{itemdecl} -constexpr iterator end() const noexcept; +typename M::index_type \end{itemdecl} \begin{itemdescr} \pnum -\returns -An iterator which is the past-the-end value. +\result +\tcode{typename M::extents_type::index_type}. \end{itemdescr} -\indexlibrarymember{span}{rbegin}% \begin{itemdecl} -constexpr reverse_iterator rbegin() const noexcept; +typename M::rank_type \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return reverse_iterator(end());} +\result +\tcode{typename M::extents_type::rank_type}. \end{itemdescr} -\indexlibrarymember{span}{rend}% \begin{itemdecl} -constexpr reverse_iterator rend() const noexcept; +typename M::layout_type \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return reverse_iterator(begin());} +\result +A type \tcode{MP} that meets +the layout mapping policy requirements\iref{mdspan.layout.policy.reqmts} and +for which \tcode{\exposid{is-mapping-of}} is \tcode{true}. \end{itemdescr} -\rSec3[span.objectrep]{Views of object representation} - -\indexlibraryglobal{as_bytes}% \begin{itemdecl} -template - span - as_bytes(span s) noexcept; +m.extents() \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return R\{reinterpret_cast(s.data()), s.size_bytes()\};} -where \tcode{R} is the return type. +\result +\tcode{const typename M::extents_type\&} \end{itemdescr} -\indexlibraryglobal{as_writable_bytes}% \begin{itemdecl} -template - span - as_writable_bytes(span s) noexcept; +m(i...) \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{is_const_v} is \tcode{false}. +\result +\tcode{typename M::index_type} \pnum -\effects -Equivalent to: \tcode{return R\{reinterpret_cast(s.data()), s.size_bytes()\};} -where \tcode{R} is the return type. +\returns +A nonnegative integer +less than \tcode{numeric_limits::max()} and +less than or equal to \tcode{numeric_limits::max()}. \end{itemdescr} -\rSec2[views.multidim]{Multidimensional access} - -\rSec3[mdspan.overview]{Overview} - -\pnum -A \defnadj{multidimensional}{index space} is -a Cartesian product of integer intervals. -Each interval can be represented by a half-open range $[L_i, U_i)$, -where $L_i$ and $U_i$ are the lower and upper bounds of -the $i^\text{th}$ dimension. -The \defn{rank} of a multidimensional index space is -the number of intervals it represents. -The \defn{size of a multidimensional index space} is -the product of $U_i - L_i$ for each dimension $i$ -if its rank is greater than 0, and 1 otherwise. +\begin{itemdecl} +m(i...) == m(static_cast(i)...) +\end{itemdecl} +\begin{itemdescr} \pnum -An integer $r$ is a \defn{rank index} of an index space $S$ -if $r$ is in the range $[0, \text{rank of $S$})$. +\result +\tcode{bool} \pnum -A pack of integers \tcode{idx} is -a \defnadj{multidimensional}{index} in a multidimensional index space $S$ -(or representation thereof) if both of the following are true: -\begin{itemize} -\item -\tcode{sizeof...(idx)} is equal to the rank of $S$, and -\item -for every rank index $i$ of $S$, -the $i^\text{th}$ value of \tcode{idx} is an integer -in the interval $[L_i, U_i)$ of $S$. -\end{itemize} - -\rSec3[mdspan.syn]{Header \tcode{} synopsis} - -\indexheader{mdspan}% -\begin{codeblock} -namespace std { - // \ref{mdspan.extents}, class template \tcode{extents} - template - class extents; - - // \ref{mdspan.extents.dextents}, alias template \tcode{dextents} - template - using dextents = @\seebelow@; - - // \ref{mdspan.layout}, layout mapping - struct layout_left; - struct layout_right; - struct layout_stride; - - // \ref{mdspan.accessor.default}, class template \tcode{default_accessor} - template - class default_accessor; - - // \ref{mdspan.mdspan}, class template \tcode{mdspan} - template> - class mdspan; - - // \ref{mdspan.submdspan}, \tcode{submdspan} creation - template - struct strided_slice; - - template - struct submdspan_mapping_result; - - template - constexpr auto submdspan_extents(const extents&, SliceSpecifiers...); - - // \ref{mdspan.submdspan.submdspan}, \tcode{submdspan} function template - template - constexpr auto submdspan( - const mdspan& src, - SliceSpecifiers... slices) -> @\seebelow@; - - template - concept @\defexposconcept{integral-constant-like}@ = // \expos - is_integral_v && - !is_same_v> && - @\libconcept{convertible_to}@ && - @\libconcept{equality_comparable_with}@ && - bool_constant::value && - bool_constant(T()) == T::value>::value; - - template - concept @\defexposconcept{index-pair-like}@ = // \expos - @\exposconcept{pair-like}@ && - @\libconcept{convertible_to}@, IndexType> && - @\libconcept{convertible_to}@, IndexType>; -} -\end{codeblock} - -\rSec3[mdspan.extents]{Class template \tcode{extents}} - -\rSec4[mdspan.extents.overview]{Overview} - -The class template \tcode{extents} represents -a multidimensional index space of rank equal to \tcode{sizeof...(Extents)}. -In subclause \iref{views}, -\tcode{extents} is used synonymously with multidimensional index space. - -\begin{codeblock} -namespace std { - template - class @\libglobal{extents}@ { - public: - using index_type = IndexType; - using size_type = make_unsigned_t; - using rank_type = size_t; - - // \ref{mdspan.extents.obs}, observers of the multidimensional index space - static constexpr rank_type rank() noexcept { return sizeof...(Extents); } - static constexpr rank_type rank_dynamic() noexcept { return @\exposid{dynamic-index}@(rank()); } - static constexpr size_t static_extent(rank_type) noexcept; - constexpr index_type extent(rank_type) const noexcept; - - // \ref{mdspan.extents.cons}, constructors - constexpr extents() noexcept = default; - - template - constexpr explicit(@\seebelow@) - extents(const extents&) noexcept; - template - constexpr explicit extents(OtherIndexTypes...) noexcept; - template - constexpr explicit(N != rank_dynamic()) - extents(span) noexcept; - template - constexpr explicit(N != rank_dynamic()) - extents(const array&) noexcept; +\returns +\tcode{true} +\end{itemdescr} - // \ref{mdspan.extents.cmp}, comparison operators - template - friend constexpr bool operator==(const extents&, - const extents&) noexcept; +\begin{itemdecl} +m.required_span_size() +\end{itemdecl} - // \ref{mdspan.extents.expo}, exposition-only helpers - constexpr size_t @\exposid{fwd-prod-of-extents}@(rank_type) const noexcept; // \expos - constexpr size_t @\exposid{rev-prod-of-extents}@(rank_type) const noexcept; // \expos - template - static constexpr auto @\exposid{index-cast}@(OtherIndexType&&) noexcept; // \expos +\begin{itemdescr} +\pnum +\result +\tcode{typename M::index_type} - private: - static constexpr rank_type @\exposid{dynamic-index}@(rank_type) noexcept; // \expos - static constexpr rank_type @\exposid{dynamic-index-inv}@(rank_type) noexcept; // \expos - array @\exposid{dynamic-extents}@{}; // \expos - }; +\pnum +\returns +If the size of the multidimensional index space \tcode{m.extents()} is 0, +then \tcode{0}, +else \tcode{1} plus the maximum value of \tcode{m(i...)} for all \tcode{i}. +\end{itemdescr} - template - explicit extents(Integrals...) - -> @\seebelow@; -} -\end{codeblock} +\begin{itemdecl} +m.is_unique() +\end{itemdecl} +\begin{itemdescr} \pnum -\mandates -\begin{itemize} -\item -\tcode{IndexType} is a signed or unsigned integer type, and -\item -each element of \tcode{Extents} is either equal to \tcode{dynamic_extent}, or -is representable as a value of type \tcode{IndexType}. -\end{itemize} +\result +\tcode{bool} \pnum -Each specialization of \tcode{extents} models \libconcept{regular} and -is trivially copyable. +\returns +\tcode{true} only if +for every \tcode{i} and \tcode{j} where \tcode{(i != j || ...)} is \tcode{true}, +\tcode{m(i...) != m(j...)} is \tcode{true}. +\begin{note} +A mapping can return \tcode{false} even if the condition is met. +For certain layouts, it is possibly not feasible to determine efficiently +whether the layout is unique. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +m.is_exhaustive() +\end{itemdecl} +\begin{itemdescr} \pnum -Let $E_r$ be the $r^\text{th}$ element of \tcode{Extents}. -$E_r$ is a \defnadj{dynamic}{extent} if it is equal to \tcode{dynamic_extent}, -otherwise $E_r$ is a \defnadj{static}{extent}. -Let $D_r$ be the value of \tcode{\exposid{dynamic-extents}[\exposid{dynamic-index}($r$)]} -if $E_r$ is a dynamic extent, -otherwise $E_r$. +\result +\tcode{bool} \pnum -The $r^\text{th}$ interval of the multidimensional index space -represented by an \tcode{extents} object is $[0, D_r)$. - -\rSec4[mdspan.extents.expo]{Exposition-only helpers} +\returns +\tcode{true} only if +for all $k$ in the range $[0, \tcode{m.required_span_size()})$ +there exists an \tcode{i} such that \tcode{m(i...)} equals $k$. +\begin{note} +A mapping can return \tcode{false} even if the condition is met. +For certain layouts, it is possibly not feasible to determine efficiently +whether the layout is exhaustive. +\end{note} +\end{itemdescr} \begin{itemdecl} -static constexpr rank_type @\exposid{dynamic-index}@(rank_type i) noexcept; +m.is_strided() \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{i <= rank()} is \tcode{true}. +\result +\tcode{bool} \pnum \returns -The number of $E_r$ with $r < \tcode{i}$ for which $E_r$ is a dynamic extent. +\tcode{true} only if +for every rank index $r$ of \tcode{m.extents()} there exists an integer $s_r$ +such that, +for all \tcode{i} where $(\tcode{i}+d_r)$ is +a multidimensional index in \tcode{m.extents()}\iref{mdspan.overview}, +\tcode{m((i + $d_r$)...) - m(i...)} equals $s_r$. +\begin{note} +This implies that for a strided layout +$m(i_0, \dotsc, i_k) = m(0, \dotsc, 0) + i_0 \times s_0 + \dotsb + i_k \times s_k$. +\end{note} +\begin{note} +A mapping can return \tcode{false} even if the condition is met. +For certain layouts, it is possibly not feasible to determine efficiently +whether the layout is strided. +\end{note} \end{itemdescr} \begin{itemdecl} -static constexpr rank_type @\exposid{dynamic-index-inv}@(rank_type i) noexcept; +m.stride(r) \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{i < rank_dynamic()} is \tcode{true}. +\tcode{m.is_strided()} is \tcode{true}. + +\pnum +\result +\tcode{typename M::index_type} \pnum \returns -The minimum value of $r$ -such that \tcode{\exposid{dynamic-index}($r$ + 1) == i + 1} is \tcode{true}. +$s_r$ as defined in \tcode{m.is_strided()} above. \end{itemdescr} \begin{itemdecl} -constexpr size_t @\exposid{fwd-prod-of-extents}@(rank_type i) const noexcept; +M::is_always_unique() \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{i <= rank()} is \tcode{true}. +\result +A constant expression\iref{expr.const} of type \tcode{bool}. \pnum \returns -If \tcode{i > 0} is \tcode{true}, -the product of \tcode{extent($k$)} for all $k$ in the range $[0, \tcode{i})$, -otherwise \tcode{1}. +\tcode{true} only if \tcode{m.is_unique()} is \tcode{true} +for all possible objects \tcode{m} of type \tcode{M}. +\begin{note} +A mapping can return \tcode{false} even if the above condition is met. +For certain layout mappings, it is possibly not feasible to determine +whether every instance is unique. +\end{note} \end{itemdescr} \begin{itemdecl} -constexpr size_t @\exposid{rev-prod-of-extents}@(rank_type i) const noexcept; +M::is_always_exhaustive() \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{i < rank()} is \tcode{true}. +\result +A constant expression\iref{expr.const} of type \tcode{bool}. \pnum \returns -If \tcode{i + 1 < rank()} is \tcode{true}, -the product of \tcode{extent($k$)} -for all $k$ in the range $[\tcode{i + 1}, \tcode{rank()})$, -otherwise \tcode{1}. +\tcode{true} only if \tcode{m.is_exhaustive()} is \tcode{true} +for all possible objects \tcode{m} of type \tcode{M}. +\begin{note} +A mapping can return \tcode{false} even if the above condition is met. +For certain layout mappings, it is possibly not feasible to determine +whether every instance is exhaustive. +\end{note} \end{itemdescr} \begin{itemdecl} -template - static constexpr auto @\exposid{index-cast}@(OtherIndexType&& i) noexcept; +M::is_always_strided() \end{itemdecl} \begin{itemdescr} \pnum -\effects -\begin{itemize} -\item -If \tcode{OtherIndexType} is an integral type other than \tcode{bool}, -then equivalent to \tcode{return i;}, -\item -otherwise, equivalent to \tcode{return static_cast(i);}. -\end{itemize} +\result +A constant expression\iref{expr.const} of type \tcode{bool}. + +\pnum +\returns +\tcode{true} only if \tcode{m.is_strided()} is \tcode{true} +for all possible objects \tcode{m} of type \tcode{M}. \begin{note} -This function will always return an integral type other than \tcode{bool}. -Since this function's call sites are constrained on -convertibility of \tcode{OtherIndexType} to \tcode{index_type}, -integer-class types can use the \tcode{static_cast} branch -without loss of precision. +A mapping can return \tcode{false} even if the above condition is met. +For certain layout mappings, it is possibly not feasible to determine +whether every instance is strided. \end{note} \end{itemdescr} -\rSec4[mdspan.extents.cons]{Constructors} +\rSec4[mdspan.layout.policy.reqmts]{Layout mapping policy requirements} -\indexlibraryctor{extents}% -\begin{itemdecl} -template - constexpr explicit(@\seebelow@) - extents(const extents& other) noexcept; -\end{itemdecl} +\pnum +A type \tcode{MP} meets the \defn{layout mapping policy} requirements +if for a type \tcode{E} that is a specialization of \tcode{extents}, +\tcode{MP::mapping} is valid and denotes a type \tcode{X} +that meets the layout mapping requirements\iref{mdspan.layout.reqmts}, and +for which the \grammarterm{qualified-id} \tcode{X::layout_type} is valid and +denotes the type \tcode{MP} and +the \grammarterm{qualified-id} \tcode{X::extents_type} denotes \tcode{E}. + +\rSec4[mdspan.layout.policy.overview]{Layout mapping policies} + +\begin{codeblock} +namespace std { + struct layout_left { + template + class mapping; + }; + struct layout_right { + template + class mapping; + }; + struct layout_stride { + template + class mapping; + }; + + template + struct layout_left_padded { + template class mapping; + }; + template + struct layout_right_padded { + template class mapping; + }; +} +\end{codeblock} -\begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -\tcode{sizeof...(OtherExtents) == rank()} is \tcode{true}. -\item -\tcode{((OtherExtents == dynamic_extent || Extents == dynamic_extent || OtherExtents ==\newline Extents) \&\& ...)} is \tcode{true}. -\end{itemize} +Each of \tcode{layout_left}, \tcode{layout_right}, and \tcode{layout_stride}, +as well as each specialization of +\tcode{layout_left_padded} and \tcode{layout_right_padded}, +meets the layout mapping policy requirements and is a trivially copyable type. +Furthermore, +\tcode{is_trivially_default_constructible_v} is \tcode{true} +for any such type \tcode{T}. + +\rSec4[mdspan.layout.left]{Class template \tcode{layout_left::mapping}} + +\rSec5[mdspan.layout.left.overview]{Overview} \pnum -\expects -\begin{itemize} -\item -\tcode{other.extent($r$)} equals $E_r$ -for each $r$ for which $E_r$ is a static extent, and -\item -either -\begin{itemize} -\item -\tcode{sizeof...(OtherExtents)} is zero, or -\item -\tcode{other.extent($r$)} is representable as -a value of type \tcode{index_type} for every rank index $r$ of \tcode{other}. -\end{itemize} -\end{itemize} +\tcode{layout_left} provides a layout mapping +where the leftmost extent has stride 1, and +strides increase left-to-right as the product of extents. + +\begin{codeblock} +namespace std { + template + class layout_left::mapping { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_left; + + // \ref{mdspan.layout.left.cons}, constructors + constexpr mapping() noexcept = default; + constexpr mapping(const mapping&) noexcept = default; + constexpr mapping(const extents_type&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const mapping&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const layout_right::mapping&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const LayoutLeftPaddedMapping&) noexcept; + template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping&); + + constexpr mapping& operator=(const mapping&) noexcept = default; + + // \ref{mdspan.layout.left.obs}, observers + constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } + + constexpr index_type required_span_size() const noexcept; + + template + constexpr index_type operator()(Indices...) const noexcept; + + static constexpr bool is_always_unique() noexcept { return true; } + static constexpr bool is_always_exhaustive() noexcept { return true; } + static constexpr bool is_always_strided() noexcept { return true; } + + static constexpr bool is_unique() noexcept { return true; } + static constexpr bool is_exhaustive() noexcept { return true; } + static constexpr bool is_strided() noexcept { return true; } + + constexpr index_type stride(rank_type) const noexcept; + + template + friend constexpr bool operator==(const mapping&, const mapping&) noexcept; + + private: + extents_type @\exposid{extents_}@{}; // \expos + + // \ref{mdspan.sub.map}, \tcode{submdspan} mapping specialization + template + constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos + -> @\seebelow@; + + template + friend constexpr auto submdspan_mapping( + const mapping& src, SliceSpecifiers... slices) { + return src.@\exposid{submdspan-mapping-impl}@(slices...); + } + }; +} +\end{codeblock} + +\pnum +If \tcode{Extents} is not a specialization of \tcode{extents}, +then the program is ill-formed. + +\pnum +\tcode{layout_left::mapping} is a trivially copyable type +that models \libconcept{regular} for each \tcode{E}. + +\pnum +\mandates +If \tcode{Extents::rank_dynamic() == 0} is \tcode{true}, +then the size of the multidimensional index space \tcode{Extents()} +is representable as a value of type \tcode{typename Extents::index_type}. + +\rSec5[mdspan.layout.left.cons]{Constructors} + +\indexlibraryctor{layout_left::mapping}% +\begin{itemdecl} +constexpr mapping(const extents_type& e) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\ensures -\tcode{*this == other} is \tcode{true}. +\expects +The size of the multidimensional index space \tcode{e} +is representable as a value of type \tcode{index_type}\iref{basic.fundamental}. \pnum -\remarks -The expression inside \tcode{explicit} is equivalent to: -\begin{codeblock} -(((Extents != dynamic_extent) && (OtherExtents == dynamic_extent)) || ... ) || -(numeric_limits::max() < numeric_limits::max()) -\end{codeblock} +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{e}. \end{itemdescr} -\indexlibraryctor{extents}% +\indexlibraryctor{layout_left::mapping}% \begin{itemdecl} -template - constexpr explicit extents(OtherIndexTypes... exts) noexcept; +template + constexpr explicit(!is_convertible_v) + mapping(const mapping& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{N} be \tcode{sizeof...(OtherIndexTypes)}, -and let \tcode{exts_arr} be -\tcode{array\{static_cast<\\index_type>(std::move(exts))...\}}. +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\expects +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +\end{itemdescr} + +\indexlibraryctor{layout_left::mapping}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + mapping(const layout_right::mapping& other) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum \constraints \begin{itemize} \item -\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, -\item -\tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}, and +\tcode{extents_type::rank() <= 1} is \tcode{true}, and \item -\tcode{N == rank_dynamic() || N == rank()} is \tcode{true}. -\begin{note} -One can construct \tcode{extents} from just dynamic extents, -which are all the values getting stored, or -from all the extents with a precondition. -\end{note} +\tcode{is_constructible_v} is \tcode{true}. \end{itemize} \pnum \expects -\begin{itemize} -\item -If \tcode{N != rank_dynamic()} is \tcode{true}, -\tcode{exts_arr[$r$]} equals $E_r$ -for each $r$ for which $E_r$ is a static extent, and -\item -either -\begin{itemize} -\item -\tcode{sizeof...(exts) == 0} is \tcode{true}, or -\item -each element of \tcode{exts} is representable -as a nonnegative value of type \tcode{index_type}. -\end{itemize} -\end{itemize} +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. \pnum -\ensures -\tcode{*this == extents(exts_arr)} is \tcode{true}. +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. \end{itemdescr} -\indexlibraryctor{extents}% +\indexlibraryctor{layout_left::mapping}% \begin{itemdecl} -template - constexpr explicit(N != rank_dynamic()) - extents(span exts) noexcept; -template - constexpr explicit(N != rank_dynamic()) - extents(const array& exts) noexcept; +template + constexpr explicit(!is_convertible_v) + mapping(const LayoutLeftPaddedMapping&) noexcept; \end{itemdecl} \begin{itemdescr} @@ -19336,504 +22094,521 @@ \constraints \begin{itemize} \item -\tcode{is_convertible_v} is \tcode{true}, -\item -\tcode{is_nothrow_constructible_v} is \tcode{true}, and +\tcode{\exposid{is-layout-left-padded-mapping-of}} is \tcode{true}. \item -\tcode{N == rank_dynamic() || N == rank()} is \tcode{true}. +\tcode{is_constructible_v}\newline is \tcode{true}. \end{itemize} \pnum -\expects +\mandates +If \begin{itemize} \item -If \tcode{N != rank_dynamic()} is \tcode{true}, -\tcode{exts[$r$]} equals $E_r$ for each $r$ for which $E_r$ is a static extent, and -\item -either -\begin{itemize} +\tcode{Extents::rank()} is greater than one, \item -\tcode{N} is zero, or +\tcode{Extents::static_extent(0)} does not equal \tcode{dynamic_extent}, and \item -\tcode{exts[$r$]} is representable -as a nonnegative value of type \tcode{index_type} for every rank index $r$. -\end{itemize} +\tcode{LayoutLeftPaddedMapping::\exposid{static-padding-stride}} +does not equal \tcode{dynamic_extent}, \end{itemize} +then \tcode{Extents::static_extent(0)} equals +\tcode{LayoutLeftPaddedMapping::\exposid{static-padding-stride}}. \pnum -\effects +\expects \begin{itemize} \item -If \tcode{N} equals \tcode{dynamic_rank()}, -for all $d$ in the range $[0, \tcode{rank_dynamic()})$, -direct-non-list-initializes \tcode{\exposidnc{dynamic-extents}[$d$]} -with \tcode{as_const(exts[$d$])}. +If \tcode{extents_type::rank() > 1} is \tcode{true}, +then \tcode{other.stride(1)} equals \tcode{other.extents(0)}. \item -Otherwise, for all $d$ in the range $[0, \tcode{rank_dynamic()})$, -direct-non-list-initializes \exposidnc{dynamic-ex\-tents}\tcode{[$d$]} -with \tcode{as_const(exts[\exposidnc{dynamic-index-inv}($d$)])}. +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}. \end{itemize} -\end{itemdescr} - -\indexlibraryctor{extents}% -\begin{itemdecl} -template - explicit extents(Integrals...) -> @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{(is_convertible_v \&\& ...)} is \tcode{true}. \pnum -\remarks -The deduced type is \tcode{dextents}. +\effects +Direct-non-list-initializes \tcode{extents_} with \tcode{other.extents()}. \end{itemdescr} -\rSec4[mdspan.extents.obs]{Observers of the multidimensional index space} - -\indexlibrarymember{static_extent}{extents}% +\indexlibraryctor{layout_left::mapping}% \begin{itemdecl} -static constexpr size_t static_extent(rank_type i) noexcept; +template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping& other); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{i < rank()} is \tcode{true}. - -\pnum -\returns -$E_\tcode{i}$. -\end{itemdescr} - -\indexlibrarymember{extent}{extents}% -\begin{itemdecl} -constexpr index_type extent(rank_type i) const noexcept; -\end{itemdecl} +\constraints +\tcode{is_constructible_v} is \tcode{true}. -\begin{itemdescr} \pnum \expects -\tcode{i < rank()} is \tcode{true}. +\begin{itemize} +\item +If \tcode{extents_type::rank() > 0} is \tcode{true}, +then for all $r$ in the range $[0, \tcode{extents_type::rank()})$, +\tcode{other.stride($r$)} equals +\tcode{other.extents().\exposid{fwd-prod-of-extents}($r$)}, and +\item +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. +\end{itemize} \pnum -\returns -$D_\tcode{i}$. +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. \end{itemdescr} -\rSec4[mdspan.extents.cmp]{Comparison operators} +\rSec5[mdspan.layout.left.obs]{Observers} -\indexlibrarymember{operator==}{extents}% +\indexlibrarymember{required_span_size}{layout_left::mapping}% \begin{itemdecl} -template - friend constexpr bool operator==(const extents& lhs, - const extents& rhs) noexcept; +constexpr index_type required_span_size() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{true} if \tcode{lhs.rank()} equals \tcode{rhs.rank()} and -if \tcode{lhs.extent(r)} equals \tcode{rhs.extent(r)} -for every rank index \tcode{r} of \tcode{rhs}, -otherwise \tcode{false}. +\tcode{extents().\exposid{fwd-prod-of-extents}(extents_type::rank())}. \end{itemdescr} -\rSec4[mdspan.extents.dextents]{Alias template \tcode{dextents}} - -\indexlibraryglobal{dextents}% +\indexlibrarymember{operator()}{layout_left::mapping}% \begin{itemdecl} -template - using dextents = @\seebelow@; +template + constexpr index_type operator()(Indices... i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -A type \tcode{E} that is a specialization of \tcode{extents} -such that \tcode{E::rank() == Rank \&\& E::rank() == E::rank_dynamic()} is \tcode{true}, and -\tcode{E::index_type} denotes \tcode{IndexType}. -\end{itemdescr} - -\rSec3[mdspan.layout]{Layout mapping} - -\rSec4[mdspan.layout.general]{General} - -\pnum -In subclauses \ref{mdspan.layout.reqmts} and \ref{mdspan.layout.policy.reqmts}: - +\constraints \begin{itemize} \item -\tcode{M} denotes a layout mapping class. - -\item -\tcode{m} denotes a (possibly const) value of type \tcode{M}. - -\item -\tcode{i} and \tcode{j} are packs of (possibly const) integers -that are multidimensional indices in \tcode{m.extents()}\iref{mdspan.overview}. -\begin{note} -The type of each element of the packs can be a different integer type. -\end{note} - +\tcode{sizeof...(Indices) == extents_type::rank()} is \tcode{true}, \item -\tcode{r} is a (possibly const) rank index of \tcode{typename M::extents_type}. - +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, and \item -$\tcode{d}_r$ is a pack of (possibly const) integers -for which \tcode{sizeof...($\tcode{d}_r$) == M::extents_type::rank()} is \tcode{true}, -the $r^\text{th}$ element is equal to 1, and -all other elements are equal to 0. +\tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}. \end{itemize} \pnum -In subclauses \ref{mdspan.layout.reqmts} through \ref{mdspan.layout.stride}, -let \exposid{is-mapping-of} be the exposition-only variable template defined as follows: -\begin{codeblock} -template -constexpr bool @\exposid{is-mapping-of}@ = // \expos - is_same_v, Mapping>; -\end{codeblock} - -\rSec4[mdspan.layout.reqmts]{Requirements} - -\pnum -A type \tcode{M} meets the \defn{layout mapping} requirements if - -\begin{itemize} -\item -\tcode{M} models \libconcept{copyable} and \libconcept{equality_comparable}, -\item -\tcode{is_nothrow_move_constructible_v} is \tcode{true}, -\item -\tcode{is_nothrow_move_assignable_v} is \tcode{true}, -\item -\tcode{is_nothrow_swappable_v} is \tcode{true}, and -\item -the following types and expressions are well-formed and -have the specified semantics. -\end{itemize} - -\begin{itemdecl} -typename M::extents_type -\end{itemdecl} +\expects +\tcode{extents_type::\exposid{index-cast}(i)} is +a multidimensional index in \exposid{extents_}\iref{mdspan.overview}. -\begin{itemdescr} \pnum -\result -A type that is a specialization of \tcode{extents}. +\effects +Let \tcode{P} be a parameter pack such that +\begin{codeblock} +is_same_v, index_sequence> +\end{codeblock} +is \tcode{true}. +Equivalent to: +\begin{codeblock} +return ((static_cast(i) * stride(P)) + ... + 0); +\end{codeblock} \end{itemdescr} +\indexlibrarymember{stride}{layout_left::mapping}% \begin{itemdecl} -typename M::index_type +constexpr index_type stride(rank_type i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -\tcode{typename M::extents_type::index_type}. -\end{itemdescr} +\constraints +\tcode{extents_type::rank() > 0} is \tcode{true}. -\begin{itemdecl} -typename M::rank_type -\end{itemdecl} +\pnum +\expects +\tcode{i < extents_type::rank()} is \tcode{true}. -\begin{itemdescr} \pnum -\result -\tcode{typename M::extents_type::rank_type}. +\returns +\tcode{extents().\exposid{fwd-prod-of-extents}(i)}. \end{itemdescr} +\indexlibrarymember{operator==}{layout_left::mapping}% \begin{itemdecl} -typename M::layout_type +template + friend constexpr bool operator==(const mapping& x, const mapping& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -A type \tcode{MP} that meets -the layout mapping policy requirements\iref{mdspan.layout.policy.reqmts} and -for which \tcode{\exposid{is-mapping-of}} is \tcode{true}. +\constraints +\tcode{extents_type::rank() == OtherExtents::rank()} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return x.extents() == y.extents();} \end{itemdescr} -\begin{itemdecl} -m.extents() -\end{itemdecl} +\rSec4[mdspan.layout.right]{Class template \tcode{layout_right::mapping}} + +\rSec5[mdspan.layout.right.overview]{Overview} -\begin{itemdescr} \pnum -\result -\tcode{const typename M::extents_type\&} -\end{itemdescr} +\tcode{layout_right} provides a layout mapping +where the rightmost extent is stride 1, and +strides increase right-to-left as the product of extents. -\begin{itemdecl} -m(i...) -\end{itemdecl} +\begin{codeblock} +namespace std { + template + class layout_right::mapping { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_right; + + // \ref{mdspan.layout.right.cons}, constructors + constexpr mapping() noexcept = default; + constexpr mapping(const mapping&) noexcept = default; + constexpr mapping(const extents_type&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const mapping&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const layout_left::mapping&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const LayoutRightPaddedMapping&) noexcept; + template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping&) noexcept; + + constexpr mapping& operator=(const mapping&) noexcept = default; + + // \ref{mdspan.layout.right.obs}, observers + constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } + + constexpr index_type required_span_size() const noexcept; + + template + constexpr index_type operator()(Indices...) const noexcept; + + static constexpr bool is_always_unique() noexcept { return true; } + static constexpr bool is_always_exhaustive() noexcept { return true; } + static constexpr bool is_always_strided() noexcept { return true; } + + static constexpr bool is_unique() noexcept { return true; } + static constexpr bool is_exhaustive() noexcept { return true; } + static constexpr bool is_strided() noexcept { return true; } + + constexpr index_type stride(rank_type) const noexcept; + + template + friend constexpr bool operator==(const mapping&, const mapping&) noexcept; + + private: + extents_type @\exposid{extents_}@{}; // \expos + + // \ref{mdspan.sub.map}, \tcode{submdspan} mapping specialization + template + constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos + -> @\seebelow@; + + template + friend constexpr auto submdspan_mapping( + const mapping& src, SliceSpecifiers... slices) { + return src.@\exposid{submdspan-mapping-impl}@(slices...); + } + }; +} +\end{codeblock} -\begin{itemdescr} \pnum -\result -\tcode{typename M::index_type} +If \tcode{Extents} is not a specialization of \tcode{extents}, +then the program is ill-formed. \pnum -\returns -A nonnegative integer -less than \tcode{numeric_limits::max()} and -less than or equal to \tcode{numeric_limits::max()}. -\end{itemdescr} +\tcode{layout_right::mapping} is a trivially copyable type +that models \libconcept{regular} for each \tcode{E}. + +\pnum +\mandates +If \tcode{Extents::rank_dynamic() == 0} is \tcode{true}, +then the size of the multidimensional index space \tcode{Extents()} +is representable as a value of type \tcode{typename Extents::index_type}. +\rSec5[mdspan.layout.right.cons]{Constructors} + +\indexlibraryctor{layout_right::mapping}% \begin{itemdecl} -m(i...) == m(static_cast(i)...) +constexpr mapping(const extents_type& e) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -\tcode{bool} +\expects +The size of the multidimensional index space \tcode{e} is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. \pnum -\returns -\tcode{true} +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{e}. \end{itemdescr} +\indexlibraryctor{layout_right::mapping}% \begin{itemdecl} -m.required_span_size() +template + constexpr explicit(!is_convertible_v) + mapping(const mapping& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -\tcode{typename M::index_type} +\constraints +\tcode{is_constructible_v} is \tcode{true}. \pnum -\returns -If the size of the multidimensional index space \tcode{m.extents()} is 0, -then \tcode{0}, -else \tcode{1} plus the maximum value of \tcode{m(i...)} for all \tcode{i}. +\expects +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. \end{itemdescr} +\indexlibraryctor{layout_right::mapping}% \begin{itemdecl} -m.is_unique() +template + constexpr explicit(!is_convertible_v) + mapping(const layout_left::mapping& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -\tcode{bool} +\constraints +\begin{itemize} +\item +\tcode{extents_type::rank() <= 1} is \tcode{true}, and +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} \pnum -\returns -\tcode{true} only if -for every \tcode{i} and \tcode{j} where \tcode{(i != j || ...)} is \tcode{true}, -\tcode{m(i...) != m(j...)} is \tcode{true}. -\begin{note} -A mapping can return \tcode{false} even if the condition is met. -For certain layouts, it is possibly not feasible to determine efficiently -whether the layout is unique. -\end{note} +\expects +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. \end{itemdescr} +\indexlibraryctor{layout_right::mapping}% \begin{itemdecl} -m.is_exhaustive() +template + constexpr explicit(!is_convertible_v) + mapping(const LayoutRightPaddedMapping&) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -\tcode{bool} +\constraints +\begin{itemize} +\item +\tcode{\exposid{is-layout-right-padded-mapping-of}} +is \tcode{true}. +\item +\tcode{is_constructible_v} +is \tcode{true}. +\end{itemize} \pnum -\returns -\tcode{true} only if -for all $k$ in the range $[0, \tcode{m.required_span_size()})$ -there exists an \tcode{i} such that \tcode{m(i...)} equals $k$. -\begin{note} -A mapping can return \tcode{false} even if the condition is met. -For certain layouts, it is possibly not feasible to determine efficiently -whether the layout is exhaustive. -\end{note} -\end{itemdescr} - -\begin{itemdecl} -m.is_strided() -\end{itemdecl} +\mandates +If +\begin{itemize} +\item +\tcode{Extents::rank()} is greater than one, +\item +\tcode{Extents::static_extent(Extents::rank() - 1)} +does not equal \tcode{dynamic_extent}, and +\item +\tcode{LayoutRightPaddedMapping::\exposid{static-padding-stride}} +does not equal \tcode{dynamic_extent}, +\end{itemize} +then \tcode{Extents::static_extent(Extents::rank() - 1)} equals +\tcode{LayoutRightPaddedMapping::\exposid{sta\-tic-padding-stride}}. -\begin{itemdescr} \pnum -\result -\tcode{bool} +\expects +\begin{itemize} +\item +If \tcode{extents_type::rank() > 1} is \tcode{true}, +then \tcode{other.stride(extents_type::rank() - 2)}\newline equals +\tcode{other.extents().extent(extents_type::rank() - 1)}. +\item +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}. +\end{itemize} \pnum -\returns -\tcode{true} only if -for every rank index $r$ of \tcode{m.extents()} there exists an integer $s_r$ -such that, -for all \tcode{i} where $(\tcode{i}+d_r)$ is -a multidimensional index in \tcode{m.extents()}\iref{mdspan.overview}, -\tcode{m((i + $d_r$)...) - m(i...)} equals $s_r$. -\begin{note} -This implies that for a strided layout -$m(i_0, \dotsc, i_k) = m(0, \dotsc, 0) + i_0 \times s_0 + \dotsb + i_k \times s_k$. -\end{note} -\begin{note} -A mapping can return \tcode{false} even if the condition is met. -For certain layouts, it is possibly not feasible to determine efficiently -whether the layout is strided. -\end{note} +\effects +Direct-non-list-initializes \tcode{extents_} with \tcode{other.extents()}. \end{itemdescr} +\indexlibraryctor{layout_right::mapping}% \begin{itemdecl} -m.stride(r) +template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{m.is_strided()} is \tcode{true}. +\constraints +\tcode{is_constructible_v} is \tcode{true}. \pnum -\result -\tcode{typename M::index_type} +\expects +\begin{itemize} +\item +If \tcode{extents_type::rank() > 0} is \tcode{true}, +then for all $r$ in the range $[0, \tcode{extents_type::rank()})$, +\tcode{other.stride($r$)} equals +\tcode{other.extents().\exposid{rev-prod-of-extents}($r$)}. +\item +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. +\end{itemize} \pnum -\returns -$s_r$ as defined in \tcode{m.is_strided()} above. +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. \end{itemdescr} +\rSec5[mdspan.layout.right.obs]{Observers} + +\indexlibrarymember{required_span_size}{layout_right::mapping}% \begin{itemdecl} -M::is_always_unique() +index_type required_span_size() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\result -A constant expression\iref{expr.const} of type \tcode{bool}. - \pnum \returns -\tcode{true} only if \tcode{m.is_unique()} is \tcode{true} -for all possible objects \tcode{m} of type \tcode{M}. -\begin{note} -A mapping can return \tcode{false} even if the above condition is met. -For certain layout mappings, it is possibly not feasible to determine -whether every instance is unique. -\end{note} +\tcode{extents().\exposid{fwd-prod-of-extents}(extents_type::rank())}. \end{itemdescr} +\indexlibrarymember{operator()}{layout_right::mapping}% \begin{itemdecl} -M::is_always_exhaustive() +template + constexpr index_type operator()(Indices... i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -A constant expression\iref{expr.const} of type \tcode{bool}. +\constraints +\begin{itemize} +\item +\tcode{sizeof...(Indices) == extents_type::rank()} is \tcode{true}, +\item +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, and +\item +\tcode{(is_nothrow_constructible_v \&\& ...)} is +\tcode{true}. +\end{itemize} \pnum -\returns -\tcode{true} only if \tcode{m.is_exhaustive()} is \tcode{true} -for all possible objects \tcode{m} of type \tcode{M}. -\begin{note} -A mapping can return \tcode{false} even if the above condition is met. -For certain layout mappings, it is possibly not feasible to determine -whether every instance is exhaustive. -\end{note} +\expects +\tcode{extents_type::\exposid{index-cast}(i)} is +a multidimensional index in \exposid{extents_}\iref{mdspan.overview}. + +\pnum +\effects +Let \tcode{P} be a parameter pack such that +\begin{codeblock} +is_same_v, index_sequence> +\end{codeblock} +is \tcode{true}. Equivalent to: +\begin{codeblock} +return ((static_cast(i) * stride(P)) + ... + 0); +\end{codeblock} \end{itemdescr} +\indexlibrarymember{stride}{layout_right::mapping}% \begin{itemdecl} -M::is_always_strided() +constexpr index_type stride(rank_type i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\result -A constant expression\iref{expr.const} of type \tcode{bool}. +\constraints +\tcode{extents_type::rank() > 0} is \tcode{true}. + +\pnum +\expects +\tcode{i < extents_type::rank()} is \tcode{true}. \pnum \returns -\tcode{true} only if \tcode{m.is_strided()} is \tcode{true} -for all possible objects \tcode{m} of type \tcode{M}. -\begin{note} -A mapping can return \tcode{false} even if the above condition is met. -For certain layout mappings, it is possibly not feasible to determine -whether every instance is strided. -\end{note} +\tcode{extents().\exposid{rev-prod-of-extents}(i)}. \end{itemdescr} -\rSec4[mdspan.layout.policy.reqmts]{Layout mapping policy requirements} +\indexlibrarymember{operator==}{layout_right::mapping}% +\begin{itemdecl} +template + friend constexpr bool operator==(const mapping& x, const mapping& y) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -A type \tcode{MP} meets the \defn{layout mapping policy} requirements -if for a type \tcode{E} that is a specialization of \tcode{extents}, -\tcode{MP::mapping} is valid and denotes a type \tcode{X} -that meets the layout mapping requirements\iref{mdspan.layout.reqmts}, and -for which the \grammarterm{qualified-id} \tcode{X::layout_type} is valid and -denotes the type \tcode{MP} and -the \grammarterm{qualified-id} \tcode{X::extents_type} denotes \tcode{E}. - -\rSec4[mdspan.layout.policy.overview]{Layout mapping policies} - -\begin{codeblock} -namespace std { - struct layout_left { - template - class mapping; - }; - struct layout_right { - template - class mapping; - }; - struct layout_stride { - template - class mapping; - }; -} -\end{codeblock} +\constraints +\tcode{extents_type::rank() == OtherExtents::rank()} is \tcode{true}. \pnum -Each of \tcode{layout_left}, \tcode{layout_right}, and \tcode{layout_stride} -meets the layout mapping policy requirements and is a trivial type. +\effects +Equivalent to: \tcode{return x.extents() == y.extents();} +\end{itemdescr} -\rSec4[mdspan.layout.left]{Class template \tcode{layout_left::mapping}} +\rSec4[mdspan.layout.stride]{Class template \tcode{layout_stride::mapping}} -\rSec5[mdspan.layout.left.overview]{Overview} +\rSec5[mdspan.layout.stride.overview]{Overview} \pnum -\tcode{layout_left} provides a layout mapping -where the leftmost extent has stride 1, and -strides increase left-to-right as the product of extents. +\tcode{layout_stride} provides a layout mapping +where the strides are user-defined. \begin{codeblock} namespace std { template - class layout_left::mapping { + class layout_stride::mapping { public: using extents_type = Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; - using layout_type = layout_left; + using layout_type = layout_stride; - // \ref{mdspan.layout.left.cons}, constructors - constexpr mapping() noexcept = default; + private: + static constexpr rank_type @\exposid{rank_}@ = extents_type::rank(); // \expos + + public: + // \ref{mdspan.layout.stride.cons}, constructors + constexpr mapping() noexcept; constexpr mapping(const mapping&) noexcept = default; - constexpr mapping(const extents_type&) noexcept; - template - constexpr explicit(!is_convertible_v) - mapping(const mapping&) noexcept; - template - constexpr explicit(!is_convertible_v) - mapping(const layout_right::mapping&) noexcept; - template - constexpr explicit(extents_type::rank() > 0) - mapping(const layout_stride::mapping&); + template + constexpr mapping(const extents_type&, span) noexcept; + template + constexpr mapping(const extents_type&, const array&) noexcept; + + template + constexpr explicit(@\seebelow@) mapping(const StridedLayoutMapping&) noexcept; constexpr mapping& operator=(const mapping&) noexcept = default; - // \ref{mdspan.layout.left.obs}, observers + // \ref{mdspan.layout.stride.obs}, observers constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } + constexpr array strides() const noexcept { return @\exposid{strides_}@; } constexpr index_type required_span_size() const noexcept; @@ -19841,25 +22616,26 @@ constexpr index_type operator()(Indices...) const noexcept; static constexpr bool is_always_unique() noexcept { return true; } - static constexpr bool is_always_exhaustive() noexcept { return true; } + static constexpr bool is_always_exhaustive() noexcept { return false; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } - static constexpr bool is_exhaustive() noexcept { return true; } + constexpr bool is_exhaustive() const noexcept; static constexpr bool is_strided() noexcept { return true; } - constexpr index_type stride(rank_type) const noexcept; + constexpr index_type stride(rank_type i) const noexcept { return @\exposid{strides_}@[i]; } - template - friend constexpr bool operator==(const mapping&, const mapping&) noexcept; + template + friend constexpr bool operator==(const mapping&, const OtherMapping&) noexcept; private: - extents_type @\exposid{extents_}@{}; // \expos + extents_type @\exposid{extents_}@{}; // \expos + array @\exposid{strides_}@{}; // \expos - // \ref{mdspan.submdspan.mapping}, \tcode{submdspan} mapping specialization + // \ref{mdspan.sub.map}, \tcode{submdspan} mapping specialization template - constexpr auto @\exposid{submdspan-mapping-impl}@( // \expos - SliceSpecifiers... slices) const -> @\seebelow@; + constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos + -> @\seebelow@; template friend constexpr auto submdspan_mapping( @@ -19875,7 +22651,7 @@ then the program is ill-formed. \pnum -\tcode{layout_left::mapping} is a trivially copyable type +\tcode{layout_stride::mapping} is a trivially copyable type that models \libconcept{regular} for each \tcode{E}. \pnum @@ -19884,51 +22660,98 @@ then the size of the multidimensional index space \tcode{Extents()} is representable as a value of type \tcode{typename Extents::index_type}. -\rSec5[mdspan.layout.left.cons]{Constructors} +\rSec5[mdspan.layout.stride.expo]{Exposition-only helpers} -\indexlibraryctor{layout_left::mapping}% -\begin{itemdecl} -constexpr mapping(const extents_type& e) noexcept; -\end{itemdecl} +\pnum +Let \tcode{\exposid{REQUIRED-SPAN-SIZE}(e, strides)} be: +\begin{itemize} +\item +\tcode{1}, if \tcode{e.rank() == 0} is \tcode{true}, +\item +otherwise \tcode{0}, if the size of the multidimensional index space \tcode{e} is 0, +\item +otherwise \tcode{1} plus the sum of products of +\tcode{(e.extent($r$) - 1)} and +\begin{codeblock} +extents_type::@\exposid{index-cast}@(strides[@$r$@]) +\end{codeblock} + for all $r$ in the range $[0, \tcode{e.rank()})$. +\end{itemize} -\begin{itemdescr} \pnum -\expects -The size of the multidimensional index space \tcode{e} -is representable as a value of type \tcode{index_type}\iref{basic.fundamental}. +Let \tcode{\exposid{OFFSET}(m)} be: +\begin{itemize} +\item +\tcode{m()}, if \tcode{e.rank() == 0} is \tcode{true}, +\item +otherwise \tcode{0}, if the size of the multidimensional index space \tcode{e} is 0, +\item +otherwise \tcode{m(z...)} for a pack of integers \tcode{z} +that is a multidimensional index in \tcode{m.extents()} and +each element of \tcode{z} equals 0. +\end{itemize} + +\pnum +Let \exposid{is-extents} be the exposition-only variable template +defined as follows: +\begin{codeblock} +template + constexpr bool @\exposid{is-extents}@ = false; // \expos +template + constexpr bool @\exposid{is-extents}@> = true; // \expos +\end{codeblock} + +\pnum +Let \exposconcept{layout-mapping-alike} be the exposition-only concept +defined as follows: +\begin{codeblock} +template +concept @\defexposconcept{layout-mapping-alike}@ = requires { // \expos + requires @\exposid{is-extents}@; + { M::is_always_strided() } -> @\libconcept{same_as}@; + { M::is_always_exhaustive() } -> @\libconcept{same_as}@; + { M::is_always_unique() } -> @\libconcept{same_as}@; + bool_constant::value; + bool_constant::value; + bool_constant::value; +}; +\end{codeblock} +\begin{note} +This concept checks that the functions +\tcode{M::is_always_strided()}, +\tcode{M::is_always_exhaustive()}, and +\tcode{M::is_always_unique()} exist, +are constant expressions, and +have a return type of \tcode{bool}. +\end{note} -\pnum -\effects -Direct-non-list-initializes \exposid{extents_} with \tcode{e}. -\end{itemdescr} +\rSec5[mdspan.layout.stride.cons]{Constructors} -\indexlibraryctor{layout_left::mapping}% +\indexlibraryctor{layout_stride::mapping}% \begin{itemdecl} -template - constexpr explicit(!is_convertible_v) - mapping(const mapping& other) noexcept; +constexpr mapping() noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v} is \tcode{true}. - \pnum \expects -\tcode{other.required_span_size()} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}. +\tcode{layout_right::mapping().required_span_size()} +is representable as a value of type \tcode{index_type}\iref{basic.fundamental}. \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +Direct-non-list-initializes \exposid{extents_} with \tcode{extents_type()}, and +for all $d$ in the range \range{0}{\exposid{rank_}}, +direct-non-list-initializes \tcode{\exposid{strides_}[$d$]} with +\tcode{layout_right::mapping().stride($d$)}. \end{itemdescr} -\indexlibraryctor{layout_left::mapping}% +\indexlibraryctor{layout_stride::mapping}% \begin{itemdecl} -template - constexpr explicit(!is_convertible_v) - mapping(const layout_right::mapping& other) noexcept; +template + constexpr mapping(const extents_type& e, span s) noexcept; +template + constexpr mapping(const extents_type& e, const array& s) noexcept; \end{itemdecl} \begin{itemdescr} @@ -19936,54 +22759,100 @@ \constraints \begin{itemize} \item -\tcode{extents_type::rank() <= 1} is \tcode{true}, and +\tcode{is_convertible_v} is \tcode{true}, and \item -\tcode{is_constructible_v} is \tcode{true}. +\tcode{is_nothrow_constructible_v} is \tcode{true}. \end{itemize} \pnum \expects -\tcode{other.required_span_size()} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}. +\begin{itemize} +\item +The result of converting \tcode{s[$i$]} to \tcode{index_type} +is greater than \tcode{0} +for all $i$ in the range $[0, \exposid{rank_})$. +\item +\tcode{\exposid{REQUIRED-SPAN-SIZE}(e, s)} is representable +as a value of type \tcode{index_type}\iref{basic.fundamental}. +\item +If \exposid{rank_} is greater than 0, +then there exists a permutation $P$ of the integers +in the range $[0, \exposid{rank_})$, +such that \tcode{s[$p_i$] >= s[$p_{i-1}$] * e.extent(p$_{i-1}$)} is \tcode{true} +for all $i$ in the range $[1, \exposid{rank_})$, +where $p_i$ is the $i^\text{th}$ element of $P$. +\begin{note} +For \tcode{layout_stride}, +this condition is necessary and sufficient +for \tcode{is_unique()} to be \tcode{true}. +\end{note} +\end{itemize} \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +Direct-non-list-initializes \exposid{extents_} with \tcode{e}, and +for all $d$ in the range $[0, \exposid{rank_})$, +direct-non-list-initializes \tcode{strides_[$d$]} with \tcode{as_const(s[$d$])}. \end{itemdescr} -\indexlibraryctor{layout_left::mapping}% +\indexlibraryctor{layout_stride::mapping}% \begin{itemdecl} -template - constexpr explicit(extents_type::rank() > 0) - mapping(const layout_stride::mapping& other); +template + constexpr explicit(@\seebelow@) + mapping(const StridedLayoutMapping& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_constructible_v} is \tcode{true}. +\begin{itemize} +\item +\tcode{\exposconcept{layout-mapping-alike}} is satisfied. +\item +\tcode{is_constructible_v} is\\\tcode{true}. +\item +\tcode{StridedLayoutMapping::is_always_unique()} is \tcode{true}. +\item +\tcode{StridedLayoutMapping::is_always_strided()} is \tcode{true}. +\end{itemize} \pnum \expects \begin{itemize} \item -If \tcode{extents_type::rank() > 0} is \tcode{true}, -then for all $r$ in the range $[0, \tcode{extents_type::rank()})$, -\tcode{other.stride($r$)} equals -\tcode{other.extents().\exposid{fwd-prod-of-extents}($r$)}, and +\tcode{StridedLayoutMapping} meets the layout mapping requirements\iref{mdspan.layout.reqmts}, +\item +\tcode{other.stride($r$) > 0} is \tcode{true} +for every rank index $r$ of \tcode{extents()}, \item \tcode{other.required_span_size()} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}. +a value of type \tcode{index_type}\iref{basic.fundamental}, and +\item +\tcode{\exposid{OFFSET}(other) == 0} is \tcode{true}. \end{itemize} \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}, and +for all $d$ in the range $[0, \exposid{rank_})$, +direct-non-list-initializes \tcode{\exposid{strides_}[$d$]} +with \tcode{other.stride($d$)}. + +\pnum +Remarks: The expression inside \tcode{explicit} is equivalent to: +\begin{codeblock} +!(is_convertible_v && + (@\exposid{is-mapping-of}@ || + @\exposid{is-mapping-of}@ || + @\exposid{is-layout-left-padded-mapping-of}@ || + @\exposid{is-layout-right-padded-mapping-of}@ || + @\exposid{is-mapping-of}@)) +\end{codeblock} \end{itemdescr} -\rSec5[mdspan.layout.left.obs]{Observers} +\rSec5[mdspan.layout.stride.obs]{Observers} -\indexlibrarymember{required_span_size}{layout_left::mapping}% +\indexlibrarymember{required_span_size}{layout_stride::mapping}% \begin{itemdecl} constexpr index_type required_span_size() const noexcept; \end{itemdecl} @@ -19991,10 +22860,10 @@ \begin{itemdescr} \pnum \returns -\tcode{extents().\exposid{fwd-prod-of-extents}(extents_type::rank())}. +\tcode{\exposid{REQUIRED-SPAN-SIZE}(extents(), \exposid{strides_})}. \end{itemdescr} -\indexlibrarymember{operator()}{layout_left::mapping}% +\indexlibrarymember{operator()}{layout_stride::mapping}% \begin{itemdecl} template constexpr index_type operator()(Indices... i) const noexcept; @@ -20005,7 +22874,7 @@ \constraints \begin{itemize} \item -\tcode{sizeof...(Indices) == extents_type::rank()} is \tcode{true}, +\tcode{sizeof...(Indices) == \exposid{rank_}} is \tcode{true}, \item \tcode{(is_convertible_v \&\& ...)} is \tcode{true}, and \item @@ -20030,152 +22899,394 @@ \end{codeblock} \end{itemdescr} -\indexlibrarymember{stride}{layout_left::mapping}% +\indexlibrarymember{is_exhaustive}{layout_stride::mapping}% \begin{itemdecl} -constexpr index_type stride(rank_type i) const; +constexpr bool is_exhaustive() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{extents_type::rank() > 0} is \tcode{true}. - -\pnum -\expects -\tcode{i < extents_type::rank()} is \tcode{true}. - \pnum \returns -\tcode{extents().\exposid{fwd-prod-of-extents}(i)}. +\begin{itemize} +\item +\tcode{true} if \exposid{rank_} is 0. +\item +Otherwise, \tcode{true} if there is +a permutation $P$ of the integers in the range $[0, \exposid{rank_})$ +such that \tcode{stride($p_0$)} equals 1, and +\tcode{stride($p_i$)} equals \tcode{stride($ p_{i-1}$) * extents().extent($p_{i-1}$)} +for $i$ in the range $[1, \exposid{rank_})$, +where $p_i$ is the $i^\text{th}$ element of $P$. +\item +Otherwise, \tcode{false}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{operator==}{layout_left::mapping}% +\indexlibrarymember{operator==}{layout_stride::mapping}% \begin{itemdecl} -template - friend constexpr bool operator==(const mapping& x, const mapping& y) noexcept; +template + friend constexpr bool operator==(const mapping& x, const OtherMapping& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{extents_type::rank() == OtherExtents::rank()} is \tcode{true}. +\begin{itemize} +\item +\tcode{\exposconcept{layout-mapping-alike}} is satisfied. +\item +\tcode{\exposid{rank_} == OtherMapping::extents_type::rank()} is \tcode{true}. +\item +\tcode{OtherMapping::is_always_strided()} is \tcode{true}. +\end{itemize} \pnum -\effects -Equivalent to: \tcode{return x.extents() == y.extents();} +\expects +\tcode{OtherMapping} meets the layout mapping requirements\iref{mdspan.layout.policy.reqmts}. + +\pnum +\returns +\tcode{true} if \tcode{x.extents() == y.extents()} is \tcode{true}, +\tcode{\exposid{OFFSET}(y) == 0} is \tcode{true}, and +each of \tcode{x.stride($r$) == y.stride($r$)} is \tcode{true} +for $r$ in the range $[0, \tcode{x.extents().rank()})$. +Otherwise, \tcode{false}. \end{itemdescr} -\rSec4[mdspan.layout.right]{Class template \tcode{layout_right::mapping}} +\rSec4[mdspan.layout.leftpad]{Class template \tcode{layout_left_padded::mapping}} -\rSec5[mdspan.layout.right.overview]{Overview} +\rSec5[mdspan.layout.leftpad.overview]{Overview} \pnum -\tcode{layout_right} provides a layout mapping -where the rightmost extent is stride 1, and -strides increase right-to-left as the product of extents. +\tcode{layout_left_padded} provides a layout mapping +that behaves like \tcode{layout_left::mapping}, +except that the padding stride \tcode{stride(1)} +can be greater than or equal to \tcode{extent(0)}. \begin{codeblock} namespace std { + template template - class layout_right::mapping { + class layout_left_padded::mapping { public: + static constexpr size_t padding_value = PaddingValue; + using extents_type = Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; - using layout_type = layout_right; + using layout_type = layout_left_padded; - // \ref{mdspan.layout.right.cons}, constructors - constexpr mapping() noexcept = default; + private: + static constexpr size_t @\exposid{rank_}@ = extents_type::rank(); // \expos + static constexpr size_t @\exposid{first-static-extent}@ = // \expos + extents_type::static_extent(0); + + // \ref{mdspan.layout.leftpad.expo}, exposition-only members + static constexpr size_t @\exposid{static-padding-stride}@ = @\seebelow@; // \expos + + public: + // \ref{mdspan.layout.leftpad.cons}, constructors + constexpr mapping() noexcept : mapping(extents_type{}) {} constexpr mapping(const mapping&) noexcept = default; - constexpr mapping(const extents_type&) noexcept; - template - constexpr explicit(!is_convertible_v) - mapping(const mapping&) noexcept; + constexpr mapping(const extents_type&); + template + constexpr mapping(const extents_type&, OtherIndexType); template constexpr explicit(!is_convertible_v) - mapping(const layout_left::mapping&) noexcept; + mapping(const layout_left::mapping&); template constexpr explicit(extents_type::rank() > 0) - mapping(const layout_stride::mapping&) noexcept; + mapping(const layout_stride::mapping&); + template + constexpr explicit(@\seebelow@) + mapping(const LayoutLeftPaddedMapping&); + template + constexpr explicit(@\seebelow@) + mapping(const LayoutRightPaddedMapping&) noexcept; constexpr mapping& operator=(const mapping&) noexcept = default; - // \ref{mdspan.layout.right.obs}, observers + // \ref{mdspan.layout.leftpad.obs}, observers constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } + constexpr array strides() const noexcept; constexpr index_type required_span_size() const noexcept; + template + constexpr index_type operator()(Indices...) const noexcept; + + static constexpr bool is_always_unique() noexcept { return true; } + static constexpr bool is_always_exhaustive() noexcept; + static constexpr bool is_always_strided() noexcept { return true; } + + static constexpr bool is_unique() noexcept { return true; } + constexpr bool is_exhaustive() const noexcept; + static constexpr bool is_strided() noexcept { return true; } + + constexpr index_type stride(rank_type) const noexcept; + + template + friend constexpr bool operator==(const mapping&, const LayoutLeftPaddedMapping&) noexcept; + + private: + // \ref{mdspan.layout.leftpad.expo}, exposition-only members + index_type @\exposid{stride-1}@ = @\exposid{static-padding-stride}@; // \expos + extents_type @\exposid{extents_}@{}; // \expos + // \ref{mdspan.sub.map}, submdspan mapping specialization + template + constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos + -> @\seebelow@; + + template + friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) { + return src.@\exposid{submdspan-mapping-impl}@(slices...); + } + }; +} +\end{codeblock} + +\pnum +If \tcode{Extents} is not a specialization of \tcode{extents}, +then the program is ill-formed. + +\pnum +\tcode{layout_left_padded::mapping} is a trivially copyable type +that models \libconcept{regular} for each \tcode{E}. + +\pnum +Throughout \ref{mdspan.layout.leftpad}, +let \tcode{P_rank} be the following +size \exposid{rank_} parameter pack of \tcode{size_}t values: +\begin{itemize} +\item +the empty parameter pack, if \exposid{rank_} equals zero; +\item +\tcode otherwise, \tcode{0zu}, if \exposid{rank_} equals one; +\item +otherwise, the parameter pack \tcode{0zu}, \tcode{1zu}, \ldots, \tcode{\exposid{rank_}- 1}. +\end{itemize} + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{rank_dynamic() == 0} is \tcode{true}, +then the size of the multidimensional index space \tcode{Extents()} +is representable as a value of type \tcode{index_type}. +\item +\tcode{padding_value} is representable as a value of type \tcode{index_type}. +\item +If +\begin{itemize} +\item +\exposid{rank_} is greater than one, +\item +\tcode{padding_value} does not equal \tcode{dynamic_extent}, and +\item +\exposid{first-static-extent} does not equal \tcode{dynamic_extent}, +\end{itemize} +then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, \exposid{first-static-extent})} +is representable as a val\-ue of type \tcode{size_t}, and +is representable as a value of type \tcode{index_type}. +\item +If +\begin{itemize} +\item +\exposid{rank_} is greater than one, +\item +\tcode{padding_value} does not equal \tcode{dynamic_extent}, and +\item +\tcode{extents_type::static_extent($k$)} does not equal \tcode{dynamic_extent} +for all $k$ in the range \range{0}{extents_type::rank()}, +\end{itemize} +then the product of +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.static_extent(0))} and +all values \tcode{ext.static_extent($k$)} +with $k$ in the range of \range{1}{\exposid{rank_}} +is representable as a value of type \tcode{size_t}, and +is representable as a value of type \tcode{index_type}. +\end{itemize} - template - constexpr index_type operator()(Indices...) const noexcept; +\rSec5[mdspan.layout.leftpad.expo]{Exposition-only members} - static constexpr bool is_always_unique() noexcept { return true; } - static constexpr bool is_always_exhaustive() noexcept { return true; } - static constexpr bool is_always_strided() noexcept { return true; } +\begin{itemdecl} +static constexpr size_t @\exposid{static-padding-stride}@ = @\seebelow@; +\end{itemdecl} - static constexpr bool is_unique() noexcept { return true; } - static constexpr bool is_exhaustive() noexcept { return true; } - static constexpr bool is_strided() noexcept { return true; } +\begin{itemdescr} +\pnum +The value is +\begin{itemize} +\item +\tcode{0}, if \exposid{rank_} equals zero or one; +\item +otherwise, \tcode{dynamic_extent}, +if \tcode{padding_value} or \exposid{first-static-extent} equals +\tcode{dynamic_extent}; +\item +otherwise, the \tcode{size_t} value which is +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, \exposid{first-sta\-tic-extent})}. +\end{itemize} +\end{itemdescr} - constexpr index_type stride(rank_type) const noexcept; +\begin{itemdecl} +index_type @\exposid{stride-1}@ = @\exposid{static-padding-stride}@; +\end{itemdecl} - template - friend constexpr bool operator==(const mapping&, const mapping&) noexcept; +\begin{itemdescr} +\pnum +\recommended +Implementations should not store this value +if \exposid{static-padding-stride} is not \tcode{dynamic_extent}. +\begin{note} +Using \tcode{extents} instead of +\tcode{index_type} as the type of \exposid{stride-1} would achieve this. +\end{note} +\end{itemdescr} - private: - extents_type @\exposid{extents_}@{}; // \expos +\rSec5[mdspan.layout.leftpad.cons]{Constructors} - // \ref{mdspan.submdspan.mapping}, \tcode{submdspan} mapping specialization - template - constexpr auto @\exposid{submdspan-mapping-impl}@( // \expos - SliceSpecifiers... slices) const -> @\seebelow@; +\indexlibraryctor{layout_left_padded::mapping}% +\begin{itemdecl} +constexpr mapping(const extents_type& ext); +\end{itemdecl} - template - friend constexpr auto submdspan_mapping( - const mapping& src, SliceSpecifiers... slices) { - return src.@\exposid{submdspan-mapping-impl}@(slices...); - } - }; -} -\end{codeblock} +\begin{itemdescr} +\pnum +\expects +\begin{itemize} +\item +The size of the multidimensional index space \tcode{ext} is representable as +a value of type \tcode{index_type}. +\item +If \exposid{rank_} is greater than one and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then \tcode{\exposid{LEAST-MUL\-TIPLE-AT-LEAST}(padding_value, ext.extent(0))} +is representable as a value of type \exposid{index_type}. +\item +If \exposid{rank_} is greater than one and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then the product of +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.extent(0))} and +all values \tcode{ext.extent($k$)} +with $k$ in the range of \range{1}{\exposid{rank_}} +is representable as a value of type \tcode{index_type}. +\end{itemize} \pnum -If \tcode{Extents} is not a specialization of \tcode{extents}, -then the program is ill-formed. +\effects +\begin{itemize} +\item +Direct-non-list-initializes \exposid{extents_} with \tcode{ext}; and +\item +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-1} +\begin{itemize} +\item +with \tcode{ext.extent(0)} if padding_value is \tcode{dynamic_extent}, +\item +otherwise with +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.extent(0))}. +\end{itemize} +\end{itemize} +\end{itemdescr} + +\indexlibraryctor{layout_left_padded::mapping}% +\begin{itemdecl} +template +constexpr mapping(const extents_type& ext, OtherIndexType pad); +\end{itemdecl} +\begin{itemdescr} \pnum -\tcode{layout_right::mapping} is a trivially copyable type -that models \libconcept{regular} for each \tcode{E}. +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}. +\item +\tcode{is_nothrow_constructible_v} is \tcode{true}. +\end{itemize} \pnum -\mandates -If \tcode{Extents::rank_dynamic() == 0} is \tcode{true}, -then the size of the multidimensional index space \tcode{Extents()} -is representable as a value of type \tcode{typename Extents::index_type}. +\expects +\begin{itemize} +\item +\tcode{pad} is representable as a value of type \tcode{index_type}. +\item +\tcode{extents_type::index-cast(pad)} is greater than zero. +\item +If \exposid{rank_} is greater than one, +then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(0))} +is representable as a value of type \tcode{index_type.} +\item +If \exposid{rank_} is greater than one, +then the product of +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(\linebreak 0))} and +all values \tcode{ext.extent($k$)} +with $k$ in the range of \range{1}{\exposid{rank_}} +is representable as a value of type \tcode{index_type}. +\item +If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, +\tcode{padding_value} equals \tcode{extents_type::\exposid{in\-dex-cast}(pad)}. +\end{itemize} -\rSec5[mdspan.layout.right.cons]{Constructors} +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{ext}, and +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-1} with +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(0))}. +\end{itemdescr} -\indexlibraryctor{layout_right::mapping}% +\indexlibraryctor{layout_left_padded::mapping}% \begin{itemdecl} -constexpr mapping(const extents_type& e) noexcept; +template + constexpr explicit(!is_convertible_v) + mapping(const layout_left::mapping& other); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\mandates +If \tcode{OtherExtents::rank()} is greater than \tcode{1}, then +\begin{codeblock} +(@\exposid{static-padding-stride}@ == dynamic_extent) || +(OtherExtents::static_extent(0) == dynamic_extent) || +(@\exposid{static-padding-stride}@ == OtherExtents::static_extent(0)) +\end{codeblock} +is \tcode{true}. + \pnum \expects -The size of the multidimensional index space \tcode{e} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}. +\begin{itemize} +\item +If \tcode{extents_type::rank() > 1} is \tcode{true} and +\tcode{padding_value} == \tcode{dynamic_extent} is \tcode{false}, +then \tcode{other.stride(1)} equals +\begin{codeblock} +@\exposid{LEAST-MULTIPLE-AT-LEAST}@(padding_value, + extents_type::@\exposid{index-cast}@(other.extents().extent(0))) +\end{codeblock} +and +\item +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}. +\end{itemize} \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{e}. +Equivalent to \tcode{mapping(other.extents())}. \end{itemdescr} -\indexlibraryctor{layout_right::mapping}% +\indexlibraryctor{layout_left_padded::mapping}% \begin{itemdecl} template - constexpr explicit(!is_convertible_v) - mapping(const mapping& other) noexcept; + constexpr explicit(rank_ > 0) + mapping(const layout_stride::mapping& other); \end{itemdecl} \begin{itemdescr} @@ -20185,19 +23296,47 @@ \pnum \expects +\begin{itemize} +\item +If \exposid{rank_} is greater than \tcode{1} and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then \tcode{other.\linebreak stride(1)} equals +\begin{codeblock} +@\exposid{LEAST-MULTIPLE-AT-LEAST}@(padding_value, + extents_type::@\exposid{index-cast}@(other.extents().extent(0))) +\end{codeblock} +\item +If \exposid{rank_} is greater than 0, +then \tcode{other.stride(0)} equals 1. +\item +If \exposid{rank_} is greater than 2, +then for all $r$ in the range \range{2}{\exposid{rank_}}, +\tcode{other.stride(r)} equals +\begin{codeblock} +(other.extents().@\exposid{fwd-prod-of-extents}@(r) / other.extents().extent(0)) * other.stride(1) +\end{codeblock} +\item \tcode{other.required_span_size()} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}. +a value of type \exposid{index_type}. +\end{itemize} \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +\begin{itemize} +\item +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()} and +\item +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-1} with +\tcode{other.stride(1)}. +\end{itemize} \end{itemdescr} -\indexlibraryctor{layout_right::mapping}% +\indexlibraryctor{layout_left_padded::mapping}% \begin{itemdecl} -template - constexpr explicit(!is_convertible_v) - mapping(const layout_left::mapping& other) noexcept; +template + constexpr explicit(@\seebelow@) + mapping(const LayoutLeftPaddedMapping& other); \end{itemdecl} \begin{itemdescr} @@ -20205,68 +23344,136 @@ \constraints \begin{itemize} \item -\tcode{extents_type::rank() <= 1} is \tcode{true}, and +\tcode{\exposid{is-layout-left-padded-mapping-of}} +is \tcode{true}. \item -\tcode{is_constructible_v} is \tcode{true}. +\tcode{is_constructible_v} +\newline is \tcode{true}. \end{itemize} \pnum -\expects +\mandates +If \exposid{rank_} is greater than 1, +then +\begin{codeblock} +padding_value == dynamic_extent || +LayoutLeftPaddedMapping::padding_value == dynamic_extent || +padding_value == LayoutLeftPaddedMapping::padding_value +\end{codeblock} +is \tcode{true}. + +\pnum +\begin{itemize} +\item +If \exposid{rank_} is greater than 1 and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then \tcode{other.\linebreak stride(1)} equals +\begin{codeblock} +@\exposid{LEAST-MULTIPLE-AT-LEAST}@(padding_value, + extents_type::@\exposid{index-cast}@(other.extent(0))) +\end{codeblock} +\item \tcode{other.required_span_size()} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}. +a value of type \tcode{index_type}. +\end{itemize} \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +\begin{itemize} +\item +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()} and +\item +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-1} with \tcode{other.stride(1)}. +\end{itemize} + +\pnum +\remarks +The expression inside \tcode{explicit} is equivalent to: +\begin{codeblock} +rank_> 1 && +(padding_value != dynamic_extent || + LayoutLeftPaddedMapping::padding_value == dynamic_extent) +\end{codeblock} \end{itemdescr} -\indexlibraryctor{layout_right::mapping}% +\indexlibraryctor{layout_left_padded::mapping}% \begin{itemdecl} -template - constexpr explicit(extents_type::rank() > 0) - mapping(const layout_stride::mapping& other) noexcept; +template + constexpr explicit(@\seebelow@) + mapping(const LayoutRightPaddedMapping& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_constructible_v} is \tcode{true}. - -\pnum -\expects \begin{itemize} \item -If \tcode{extents_type::rank() > 0} is \tcode{true}, -then for all $r$ in the range $[0, \tcode{extents_type::rank()})$, -\tcode{other.stride($r$)} equals -\tcode{other.extents().\exposid{rev-prod-of-extents}($r$)}. +\tcode{\exposid{is-layout-right-padded-mapping-of}} +is \tcode{true} or\newline +\tcode{\exposid{is-mapping-of}} +is \tcode{true}. \item -\tcode{other.required_span_size()} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}. +\exposid{rank_} equals zero or one. +\item +\tcode{is_constructible_v} +is \tcode{true}. \end{itemize} +\pnum +\expects +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}. + \pnum \effects Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. + +\pnum +\remarks +The expression inside \tcode{explicit} is equivalent to: +\begin{codeblock} +!is_convertible_v +\end{codeblock} + +\begin{note} +Neither the input mapping nor the mapping to be constructed +uses the padding stride in the rank-0 or rank-1 case, +so the padding stride does not affect +either the constraints or the preconditions. +\end{note} \end{itemdescr} -\rSec5[mdspan.layout.right.obs]{Observers} +\rSec5[mdspan.layout.leftpad.obs]{Observers} -\indexlibrarymember{required_span_size}{layout_right::mapping}% \begin{itemdecl} -index_type required_span_size() const noexcept; +constexpr array strides() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{extents().\exposid{fwd-prod-of-extents}(extents_type::rank())}. +\tcode{array(\{stride(P_rank)...\})}. +\end{itemdescr} + +\begin{itemdecl} +constexpr index_type required_span_size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item +\tcode{0} if the multidimensional index space \exposid{extents_} is empty, +\item +otherwise, \tcode{*this(((\exposid{extents_}(P_rank) - index_type(1))...)) + 1}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{operator()}{layout_right::mapping}% \begin{itemdecl} template - constexpr index_type operator()(Indices... i) const noexcept; +constexpr size_t operator()(Indices... idxs) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -20274,105 +23481,158 @@ \constraints \begin{itemize} \item -\tcode{sizeof...(Indices) == extents_type::rank()} is \tcode{true}, +\tcode{sizeof...(Indices) == \exposid{rank_}} is \tcode{true}. \item -\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, and +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}. \item -\tcode{(is_nothrow_constructible_v \&\& ...)} is -\tcode{true}. +\tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}. \end{itemize} \pnum \expects -\tcode{extents_type::\exposid{index-cast}(i)} is -a multidimensional index in \exposid{extents_}\iref{mdspan.overview}. +\tcode{extents_type::\exposid{index-cast}(idxs)} is +a multidimensional index in \tcode{extents()}\iref{mdspan.overview}. \pnum -\effects -Let \tcode{P} be a parameter pack such that -\begin{codeblock} -is_same_v, index_sequence> -\end{codeblock} -is \tcode{true}. Equivalent to: -\begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); -\end{codeblock} +\returns +\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. \end{itemdescr} -\indexlibrarymember{stride}{layout_right::mapping}% \begin{itemdecl} -constexpr index_type stride(rank_type i) const noexcept; +static constexpr bool is_always_exhaustive() noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{extents_type::rank() > 0} is \tcode{true}. +\returns +\begin{itemize} +\item +If \exposid{rank_} equals zero or one, then \tcode{true}; +\item +otherwise, if +neither \exposid{static-padding-stride} nor \exposid{first-static-extent} +equal \tcode{dynamic_extent}, +then \tcode{\exposid{static-padding-stride} == \exposid{first-static-extent}}; +\item +otherwise, \tcode{false}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +constexpr bool is_exhaustive() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \exposid{rank_} equals zero or one; +otherwise, \tcode{extents_.extent(0) == stride(1)}. +\end{itemdescr} + +\begin{itemdecl} +constexpr index_type stride(rank_type r) const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum \expects -\tcode{i < extents_type::rank()} is \tcode{true}. +\tcode{r} is smaller than \exposid{rank_}. \pnum \returns -\tcode{extents().\exposid{rev-prod-of-extents}(i)}. +\begin{itemize} +\item +If \tcode{r} equals zero: 1; +\item +otherwise, if \tcode{r} equals one: \exposid{stride-1}; +\item +otherwise, the product of \exposid{stride-1} and +all values \tcode{extents_.extent($k$)} with $k$ in the range \range{1}{r}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{operator==}{layout_right::mapping}% \begin{itemdecl} -template - friend constexpr bool operator==(const mapping& x, const mapping& y) noexcept; +template + friend constexpr bool operator==(const mapping& x, const LayoutLeftPaddedMapping& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{extents_type::rank() == OtherExtents::rank()} is \tcode{true}. +\begin{itemize} +\item +\tcode{\exposid{is-layout-left-padded-mapping-of}} +is \tcode{true}. +\item +\tcode{LayoutLeftPaddedMapping::extents_type::rank() == rank_} is \tcode{true}. +\end{itemize} \pnum -\effects -Equivalent to: \tcode{return x.extents() == y.extents();} +\returns +\tcode{true} if \tcode{x.extents() == y.extents()} is \tcode{true} and +\tcode{\exposid{rank_} < 2 || x.stride(1) == y.\newline stride(1)} is \tcode{true}. +Otherwise, \tcode{false}. \end{itemdescr} -\rSec4[mdspan.layout.stride]{Class template \tcode{layout_stride::mapping}} +\rSec4[mdspan.layout.rightpad]{Class template \tcode{layout_right_padded::mapping}} -\rSec5[mdspan.layout.stride.overview]{Overview} +\rSec5[mdspan.layout.rightpad.overview]{Overview} \pnum -\tcode{layout_stride} provides a layout mapping -where the strides are user-defined. +\tcode{layout_right_padded} provides a layout mapping +that behaves like \tcode{layout_right::mapping}, +except that the padding stride \tcode{stride(extents_type::rank() - 2)} +can be greater than or equal to +\tcode{extents_type::ex\-tent(extents_type::rank() - 1)}. \begin{codeblock} namespace std { + template template - class layout_stride::mapping { + class layout_right_padded::mapping { public: + static constexpr size_t padding_value = PaddingValue; + using extents_type = Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; - using layout_type = layout_stride; + using layout_type = layout_right_padded; private: - static constexpr rank_type @\exposid{rank_}@ = extents_type::rank(); // \expos + static constexpr size_t @\exposid{rank_}@ = extents_type::rank(); // \expos + static constexpr size_t @\exposid{last-static-extent}@ = // \expos + extents_type::static_extent(@\exposid{rank_}@ - 1); + + // \ref{mdspan.layout.rightpad.expo}, exposition-only members + static constexpr size_t @\exposid{static-padding-stride}@ = @\seebelow@; // \expos public: - // \ref{mdspan.layout.stride.cons}, constructors - constexpr mapping() noexcept; + // \ref{mdspan.layout.rightpad.cons}, constructors + constexpr mapping() noexcept : mapping(extents_type{}) {} constexpr mapping(const mapping&) noexcept = default; + constexpr mapping(const extents_type&); template - constexpr mapping(const extents_type&, span) noexcept; - template - constexpr mapping(const extents_type&, const array&) noexcept; + constexpr mapping(const extents_type&, OtherIndexType); - template - constexpr explicit(@\seebelow@) mapping(const StridedLayoutMapping&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const layout_right::mapping&); + template + constexpr explicit(rank_ > 0) + mapping(const layout_stride::mapping&); + template + constexpr explicit(@\seebelow@) + mapping(const LayoutRightPaddedMapping&); + template + constexpr explicit(@\seebelow@) + mapping(const LayoutLeftPaddedMapping&) noexcept; constexpr mapping& operator=(const mapping&) noexcept = default; - // \ref{mdspan.layout.stride.obs}, observers - constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } - constexpr array strides() const noexcept { return @\exposid{strides_}@; } + // \ref{mdspan.layout.rightpad.obs}, observers + constexpr const extents_type& extents() const noexcept { return extents_; } + constexpr array strides() const noexcept; constexpr index_type required_span_size() const noexcept; @@ -20380,32 +23640,32 @@ constexpr index_type operator()(Indices...) const noexcept; static constexpr bool is_always_unique() noexcept { return true; } - static constexpr bool is_always_exhaustive() noexcept { return false; } + static constexpr bool is_always_exhaustive() noexcept; static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } constexpr bool is_exhaustive() const noexcept; static constexpr bool is_strided() noexcept { return true; } - constexpr index_type stride(rank_type i) const noexcept { return @\exposid{strides_}@[i]; } + constexpr index_type stride(rank_type) const noexcept; - template - friend constexpr bool operator==(const mapping&, const OtherMapping&) noexcept; + template + friend constexpr bool operator==(const mapping&, const LayoutRightPaddedMapping&) noexcept; private: - extents_type @\exposid{extents_}@{}; // \expos - array @\exposid{strides_}@{}; // \expos + // \ref{mdspan.layout.rightpad.expo}, exposition-only members + index_type @\exposid{stride-rm2}@ = @\exposid{static-padding-stride}@; // \expos + extents_type @\exposid{extents_}@{}; // \expos - // \ref{mdspan.submdspan.mapping}, \tcode{submdspan} mapping specialization + // \ref{mdspan.sub.map}, submdspan mapping specialization template - constexpr auto @\exposid{submdspan-mapping-impl}@( // \expos - SliceSpecifiers... slices) const -> @\seebelow@; + constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos + -> @\seebelow@; template - friend constexpr auto submdspan_mapping( - const mapping& src, SliceSpecifiers... slices) { - return src.@\exposid{submdspan-mapping-impl}@(slices...); - } + friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) { + return src.@\exposid{submdspan-mapping-impl}@(slices...); + } }; } \end{codeblock} @@ -20415,155 +23675,362 @@ then the program is ill-formed. \pnum -\tcode{layout_stride::mapping} is a trivially copyable type +\tcode{layout_right_padded::mapping} is a trivially copyable type that models \libconcept{regular} for each \tcode{E}. +\pnum +Throughout \ref{mdspan.layout.rightpad}, +let \tcode{P_rank} be the following +size \exposid{rank_} parameter pack of \tcode{size_}t values: +\begin{itemize} +\item +the empty parameter pack, if \exposid{rank_} equals zero; +\item +\tcode otherwise, \tcode{0zu}, if \exposid{rank_} equals one; +\item +otherwise, the parameter pack \tcode{0zu}, \tcode{1zu}, \ldots, \tcode{\exposid{rank_}- 1}. +\end{itemize} + \pnum \mandates -If \tcode{Extents::rank_dynamic() == 0} is \tcode{true}, +\begin{itemize} +\item +If \tcode{rank_dynamic() == 0} is \tcode{true}, then the size of the multidimensional index space \tcode{Extents()} -is representable as a value of type \tcode{typename Extents::index_type}. +is representable as a value of type \tcode{index_type}. +\item +\tcode{padding_value} is representable as a value of type \tcode{index_type}. +\item +If +\begin{itemize} +\item +\exposid{rank_} is greater than one, +\item +\tcode{padding_value} does not equal \tcode{dynamic_extent}, and +\item +\exposid{last-static-extent} does not equal \tcode{dynamic_extent}, +\end{itemize} +then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, \exposid{last-static-extent})} +is representable as a value of type \tcode{size_t}, and +is representable as a value of type \tcode{index_type}. +\item +If +\begin{itemize} +\item +\exposid{rank_} is greater than one, +\item +\tcode{padding_value} does not equal \tcode{dynamic_extent}, and +\item +\tcode{extents_type::static_extent($k$)} does not equal \tcode{dynamic_extent} +for all $k$ in the range \range{0}{\exposid{rank_}}, +\end{itemize} +then the product of +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.static_extent(\exposid{rank_} - 1))} and +all values \tcode{ext.static_extent($k$)} +with $k$ in the range of \range{0}{\exposid{rank_} - 1} +is representable as a value of type \tcode{size_t}, and +is representable as a value of type \tcode{index_type}. +\end{itemize} -\rSec5[mdspan.layout.stride.expo]{Exposition-only helpers} +\rSec5[mdspan.layout.rightpad.expo]{Exposition-only members} + +\begin{itemdecl} +static constexpr size_t @\exposid{static-padding-stride}@ = @\seebelow@; +\end{itemdecl} +\begin{itemdescr} \pnum -Let \tcode{\exposid{REQUIRED-SPAN-SIZE}(e, strides)} be: +The value is \begin{itemize} \item -\tcode{1}, if \tcode{e.rank() == 0} is \tcode{true}, +\tcode{0}, if \exposid{rank_} equals zero or one; \item -otherwise \tcode{0}, if the size of the multidimensional index space \tcode{e} is 0, +otherwise, \tcode{dynamic_extent}, +if \tcode{padding_value} or \exposid{last-static-extent} equals +\tcode{dynamic_extent}; \item -otherwise \tcode{1} plus the sum of products of -\tcode{(e.extent($r$) - 1)} and -\begin{codeblock} -extents_type::@\exposid{index-cast}@(strides[@$r$@]) -\end{codeblock} - for all $r$ in the range $[0, \tcode{e.rank()})$. +otherwise, the \tcode{size_t} value which is +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, \exposid{last-sta\-tic-extent})}. \end{itemize} +\end{itemdescr} + +\begin{itemdecl} +index_type @\exposid{stride-rm2}@ = @\exposid{static-padding-stride}@; +\end{itemdecl} +\begin{itemdescr} \pnum -Let \tcode{\exposid{OFFSET}(m)} be: +\recommended +Implementations should not store this value +if \exposid{static-padding-stride} is not \tcode{dynamic_extent}. +\begin{note} +Using \tcode{extents} +instead of \tcode{index_type} as the type of \exposid{stride-\linebreak rm2} +would achieve this. +\end{note} +\end{itemdescr} + +\rSec5[mdspan.layout.rightpad.cons]{Constructors} + +\indexlibraryctor{layout_right_padded::mapping}% +\begin{itemdecl} +constexpr mapping(const extents_type& ext); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects \begin{itemize} \item -\tcode{m()}, if \tcode{e.rank() == 0} is \tcode{true}, +The size of the multidimensional index space \tcode{ext} +is representable as a value of type \tcode{index_type}. +\item +If \exposid{rank_} is greater than one and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then \tcode{\exposid{LEAST-MUL\-TIPLE-AT-LEAST}(padding_value, ext.extent(\exposid{rank_} - 1))} +is representable as a value of type \exposid{index_type}. +\item +If \exposid{rank_} is greater than one and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then the product of +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.extent(\exposid{rank_} - 1))} and +all values \tcode{ext.extent($k$)} +with $k$ in the range of \range{0}{\exposid{rank_} - 1} +is representable as a value of type \tcode{index_type}. +\end{itemize} + +\pnum +\effects +\begin{itemize} \item -otherwise \tcode{0}, if the size of the multidimensional index space \tcode{e} is 0, +Direct-non-list-initializes \exposid{extents_} with \tcode{ext}; and \item -otherwise \tcode{m(z...)} for a pack of integers \tcode{z} -that is a multidimensional index in \tcode{m.extents()} and -each element of \tcode{z} equals 0. +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-rm2} +\begin{itemize} +\item +with \tcode{ext.extent(\exposid{rank_} - 1)} +if \tcode{padding_value} is \tcode{dynamic_extent}, +\item +otherwise with +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.extent(\exposid{rank_} - 1))}. \end{itemize} +\end{itemize} +\end{itemdescr} + +\indexlibraryctor{layout_right_padded::mapping}% +\begin{itemdecl} +template +constexpr mapping(const extents_type& ext, OtherIndexType pad); +\end{itemdecl} +\begin{itemdescr} \pnum -Let \exposid{is-extents} be the exposition-only variable template -defined as follows: +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}. +\item +\tcode{is_nothrow_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{pad} is representable as a value of type \tcode{index_type}. +\item +\tcode{extents_type::\exposid{index-cast}(pad)} is greater than zero. +\item +If \exposid{rank_} is greater than one, +then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(\exposid{rank_} - 1))} +is representable as a value of type \tcode{index_type}. +\item +If \exposid{rank_} is greater than one, +then the product of +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(\exposid{\linebreak rank_} - 1))} and +all values \tcode{ext.extent($k$)} +with $k$ in the range of \range{0}{\exposid{rank_} - 1} +is representable as a value of type \tcode{index_type}. +\item +If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, +\tcode{padding_value} equals \tcode{extents_type::\linebreak \exposid{index-cast}(pad)}. +\end{itemize} + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{ext}, and +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-rm2} with +\tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(\exposid{rank_} - 1))}. +\end{itemdescr} + +\indexlibraryctor{layout_right_padded::mapping}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + mapping(const layout_right::mapping& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\mandates +If \tcode{OtherExtents::rank()} is greater than 1, then \begin{codeblock} -template - constexpr bool @\exposid{is-extents}@ = false; // \expos -template - constexpr bool @\exposid{is-extents}@> = true; // \expos +(@\exposid{static-padding-stride}@ == dynamic_extent) || +(OtherExtents::static_extent(@\exposid{rank_}@ - 1) == dynamic_extent) || +(@\exposid{static-padding-stride}@ == OtherExtents::static_extent(@\exposid{rank_}@ - 1)) \end{codeblock} +is \tcode{true}. \pnum -Let \exposconcept{layout-mapping-alike} be the exposition-only concept -defined as follows: +\expects +\begin{itemize} +\item +If \tcode{\exposid{rank_} > 1} is \tcode{true} and +\tcode{padding_value == dynamic_extent} is \tcode{false}, then +\tcode{other.stride(\newline \exposid{rank_} - 2)} equals \begin{codeblock} -template -concept @\defexposconcept{layout-mapping-alike}@ = requires { // \expos - requires @\exposid{is-extents}@; - { M::is_always_strided() } -> @\libconcept{same_as}@; - { M::is_always_exhaustive() } -> @\libconcept{same_as}@; - { M::is_always_unique() } -> @\libconcept{same_as}@; - bool_constant::value; - bool_constant::value; - bool_constant::value; -}; +@\exposid{LEAST-MULTIPLE-AT-LEAST}@(padding_value, + extents_type::@\exposid{index-cast}@(other.extents().extent(rank_ - 1))) \end{codeblock} -\begin{note} -This concept checks that the functions -\tcode{M::is_always_strided()}, -\tcode{M::is_always_exhaustive()}, and -\tcode{M::is_always_unique()} exist, -are constant expressions, and -have a return type of \tcode{bool}. -\end{note} +and +\item +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}. +\end{itemize} -\rSec5[mdspan.layout.stride.cons]{Constructors} +\pnum +\effects +Equivalent to \tcode{mapping(other.extents())}. +\end{itemdescr} -\indexlibraryctor{layout_stride::mapping}% +\indexlibraryctor{layout_right_padded::mapping}% \begin{itemdecl} -constexpr mapping() noexcept; +template + constexpr explicit(rank_ > 0) + mapping(const layout_stride::mapping& other); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + \pnum \expects -\tcode{layout_right::mapping().required_span_size()} -is representable as a value of type \tcode{index_type}\iref{basic.fundamental}. +\begin{itemize} +\item +If \exposid{rank_} is greater than 1 and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then \tcode{other.\linebreak stride(\exposid{rank_} - 2)} equals +\begin{codeblock} +@\exposid{LEAST-MULTIPLE-AT-LEAST}@(padding_value, + extents_type::@\exposid{index-cast}@(other.extents().extent(@\exposid{rank_}@ - 1))) +\end{codeblock} +\item +If \exposid{rank_} is greater than 0, +then other.stride(\exposid{rank_} - 1) equals 1. +\item +If \exposid{rank_} is greater than 2, +then for all $r$ in the range \range{0}{\exposid{rank_} - 2}, +\tcode{other.stride($r$)} equals +\begin{codeblock} +(other.extents().@\exposid{rev-prod-of-extents}@(r) / other.extents().extent(@\exposid{rank_}@ - 1)) * + other.stride(@\exposid{rank_}@ - 2) +\end{codeblock} +\item +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}. +\end{itemize} \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{extents_type()}, and -for all $d$ in the range \range{0}{\exposid{rank_}}, -direct-non-list-initializes \tcode{\exposid{strides_}[$d$]} with -\tcode{layout_right::mapping().stride($d$)}. +\begin{itemize} +\item +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}; and +\item +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-rm2} +with \tcode{other.stride(\exposid{rank_} - 2)}. +\end{itemize} \end{itemdescr} -\indexlibraryctor{layout_stride::mapping}% +\indexlibraryctor{layout_right_padded::mapping}% \begin{itemdecl} -template - constexpr mapping(const extents_type& e, span s) noexcept; -template - constexpr mapping(const extents_type& e, const array& s) noexcept; +template + constexpr explicit(@\seebelow@) + mapping(const LayoutRightPaddedMapping& other); \end{itemdecl} -\begin{itemdescr} +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{\exposid{is-layout-right-padded-mapping-of}} +is \tcode{true}. +\item +\tcode{is_constructible_v} +is \tcode{true}. +\end{itemize} + +\pnum +\mandates +If \exposid{rank_} is greater than 1, then +\begin{codeblock} +padding_value == dynamic_extent || +LayoutRightPaddedMapping::padding_value == dynamic_extent || +padding_value == LayoutRightPaddedMapping::padding_value +\end{codeblock} +is \tcode{true}. + \pnum -\constraints +\expects \begin{itemize} \item -\tcode{is_convertible_v} is \tcode{true}, and +If \exposid{rank_} is greater than 1 and +\tcode{padding_value} does not equal \tcode{dynamic_extent}, +then \tcode{other.\linebreak stride(\exposid{rank_} - 2)} equals +\begin{codeblock} +@\exposid{LEAST-MULTIPLE-AT-LEAST}@(padding_value, + extents_type::@\exposid{index-cast}@(other.extent(@\exposid{rank_}@ - 1))) +\end{codeblock} \item -\tcode{is_nothrow_constructible_v} is \tcode{true}. +\tcode{other.required_span_size()} is representable as +a value of type \tcode{index_type}. \end{itemize} \pnum -\expects +\effects \begin{itemize} \item -The result of converting \tcode{s[$i$]} to \tcode{index_type} -is greater than \tcode{0} -for all $i$ in the range $[0, \exposid{rank_})$. -\item -\tcode{\exposid{REQUIRED-SPAN-SIZE}(e, s)} is representable -as a value of type \tcode{index_type}\iref{basic.fundamental}. +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}; and \item -If \exposid{rank_} is greater than 0, -then there exists a permutation $P$ of the integers -in the range $[0, \exposid{rank_})$, -such that \tcode{s[$p_i$] >= s[$p_{i-1}$] * e.extent(p$_{i-1}$)} is \tcode{true} -for all $i$ in the range $[1, \exposid{rank_})$, -where $p_i$ is the $i^\text{th}$ element of $P$. -\begin{note} -For \tcode{layout_stride}, -this condition is necessary and sufficient -for \tcode{is_unique()} to be \tcode{true}. -\end{note} +if \exposid{rank_} is greater than one, +direct-non-list-initializes \exposid{stride-rm2} +with \tcode{other.stride(rank_ - 2)}. \end{itemize} \pnum -\effects -Direct-non-list-initializes \exposid{extents_} with \tcode{e}, and -for all $d$ in the range $[0, \exposid{rank_})$, -direct-non-list-initializes \tcode{strides_[$d$]} with \tcode{as_const(s[$d$])}. +\remarks +The expression inside \tcode{explicit} is equivalent to: +\begin{codeblock} +@\exposid{rank_}@ > 1 && +(padding_value != dynamic_extent || + LayoutRightPaddedMapping::padding_value == dynamic_extent) +\end{codeblock} \end{itemdescr} -\indexlibraryctor{layout_stride::mapping}% +\indexlibraryctor{layout_right_padded::mapping}% \begin{itemdecl} -template +template constexpr explicit(@\seebelow@) - mapping(const StridedLayoutMapping& other) noexcept; + mapping(const LayoutLeftPaddedMapping& other) noexcept; \end{itemdecl} \begin{itemdescr} @@ -20571,50 +24038,53 @@ \constraints \begin{itemize} \item -\tcode{\exposconcept{layout-mapping-alike}} is satisfied. -\item -\tcode{is_constructible_v} is\\\tcode{true}. +\tcode{\exposid{is-layout-left-padded-mapping-of}} +is \tcode{true} or\newline +\tcode{\exposid{is-mapping-of}} +is \tcode{true}. \item -\tcode{StridedLayoutMapping::is_always_unique()} is \tcode{true}. +\exposid{rank_} equals zero or one. \item -\tcode{StridedLayoutMapping::is_always_strided()} is \tcode{true}. +\tcode{is_constructible_v}\newline +is \tcode{true}. \end{itemize} \pnum \expects -\begin{itemize} -\item -\tcode{StridedLayoutMapping} meets the layout mapping requirements\iref{mdspan.layout.reqmts}, -\item -\tcode{other.stride($r$) > 0} is \tcode{true} -for every rank index $r$ of \tcode{extents()}, -\item \tcode{other.required_span_size()} is representable as -a value of type \tcode{index_type}\iref{basic.fundamental}, and -\item -\tcode{\exposid{OFFSET}(other) == 0} is \tcode{true}. -\end{itemize} +a value of type \tcode{index_type}. \pnum \effects -Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}, and -for all $d$ in the range $[0, \exposid{rank_})$, -direct-non-list-initializes \tcode{\exposid{strides_}[$d$]} -with \tcode{other.stride($d$)}. +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. \pnum -Remarks: The expression inside \tcode{explicit} is equivalent to: +\remarks +The expression inside \tcode{explicit} is equivalent to: \begin{codeblock} -!(is_convertible_v && - (@\exposid{is-mapping-of}@ || - @\exposid{is-mapping-of}@ || - @\exposid{is-mapping-of}@)) +!is_convertible_v \end{codeblock} +\begin{note} +Neither the input mapping nor the mapping to be constructed +uses the padding stride in the rank-0 or rank-1 case, +so the padding stride affects neither the constraints nor the preconditions. +\end{note} \end{itemdescr} -\rSec5[mdspan.layout.stride.obs]{Observers} +\rSec5[mdspan.layout.rightpad.obs]{Observers} -\indexlibrarymember{required_span_size}{layout_stride::mapping}% +\indexlibrarymember{layout_right_padded::mapping}{strides}% +\begin{itemdecl} +constexpr array strides() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{array({stride(P_rank)...})}. +\end{itemdescr} + +\indexlibrarymember{layout_right_padded::mapping}{required_span_size}% \begin{itemdecl} constexpr index_type required_span_size() const noexcept; \end{itemdecl} @@ -20622,13 +24092,14 @@ \begin{itemdescr} \pnum \returns -\tcode{\exposid{REQUIRED-SPAN-SIZE}(extents(), \exposid{strides_})}. +\tcode{0} if the multidimensional index space \exposid{extents_} is empty, +otherwise \tcode{*this(((\exposid{extents_}(P_rank) - index_type(1))...)) + 1}. \end{itemdescr} -\indexlibrarymember{operator()}{layout_stride::mapping}% +\indexlibrarymember{layout_right_padded::mapping}{operator()}% \begin{itemdecl} template - constexpr index_type operator()(Indices... i) const noexcept; +constexpr size_t operator()(Indices... idxs) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -20636,34 +24107,26 @@ \constraints \begin{itemize} \item -\tcode{sizeof...(Indices) == \exposid{rank_}} is \tcode{true}, +\tcode{sizeof...(Indices) == \exposid{rank_}} is \tcode{true}. \item -\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, and +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}. \item \tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}. \end{itemize} \pnum \expects -\tcode{extents_type::\exposid{index-cast}(i)} is -a multidimensional index in \exposid{extents_}\iref{mdspan.overview}. +\tcode{extents_type::\exposid{index-cast}(idxs)} is +a multidimensional index in \tcode{extents()}\iref{mdspan.overview}. \pnum -\effects -Let \tcode{P} be a parameter pack such that -\begin{codeblock} -is_same_v, index_sequence> -\end{codeblock} -is \tcode{true}. -Equivalent to: -\begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); -\end{codeblock} +\returns +\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. \end{itemdescr} -\indexlibrarymember{is_exhaustive}{layout_stride::mapping}% +\indexlibrarymember{layout_right_padded::mapping}{is_always_exhaustive}% \begin{itemdecl} -constexpr bool is_exhaustive() const noexcept; +static constexpr bool is_always_exhaustive() noexcept; \end{itemdecl} \begin{itemdescr} @@ -20671,47 +24134,78 @@ \returns \begin{itemize} \item -\tcode{true} if \exposid{rank_} is 0. +If \exposid{rank_} equals zero or one, then \tcode{true}; \item -Otherwise, \tcode{true} if there is -a permutation $P$ of the integers in the range $[0, \exposid{rank_})$ -such that \tcode{stride($p_0$)} equals 1, and -\tcode{stride($p_i$)} equals \tcode{stride($ p_{i-1}$) * extents().extent($p_{i-1}$)} -for $i$ in the range $[1, \exposid{rank_})$, -where $p_i$ is the $i^\text{th}$ element of $P$. +otherwise, +if neither \exposid{static-padding-stride} nor \exposid{last-static-extent} +equal \tcode{dynamic_extent}, +then \tcode{\exposid{static-padding-stride} == \exposid{last-static-extent}}; \item -Otherwise, \tcode{false}. +otherwise, \tcode{false}. \end{itemize} \end{itemdescr} -\indexlibrarymember{operator==}{layout_stride::mapping}% +\indexlibrarymember{layout_right_padded::mapping}{is_exhaustive}% \begin{itemdecl} -template - friend constexpr bool operator==(const mapping& x, const OtherMapping& y) noexcept; +constexpr bool is_exhaustive() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints +\returns +\tcode{true} if \exposid{rank_} equals zero or one; +otherwise, +\begin{codeblock} +@\exposid{extents_}@.extent(@\exposid{rank_}@ - 1) == stride(@\exposid{rank_}@ - 2) +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr index_type stride(rank_type r) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{r} is smaller than \exposid{rank_}. + +\pnum +\returns \begin{itemize} \item -\tcode{\exposconcept{layout-mapping-alike}} is satisfied. +If \tcode{r} equals \tcode{\exposid{rank_} - 1}: \tcode{1}; \item -\tcode{\exposid{rank_} == OtherMapping::extents_type::rank()} is \tcode{true}. +otherwise, if \tcode{r} equals \tcode{\exposid{rank_} - 2}: \exposid{stride-rm2}; \item -\tcode{OtherMapping::is_always_strided()} is \tcode{true}. +otherwise, +the product of \exposid{stride-rm2} and +all values \tcode{extents_.extent($k$)} +with $k$ in the range of \range{r + 1}{\exposid{rank_} - 1}. \end{itemize} +\end{itemdescr} + +\indexlibrarymember{layout_right_padded::mapping}{operator==}% +\begin{itemdecl} +template + friend constexpr bool operator==(const mapping& x, const LayoutRightPaddedMapping& y) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\expects -\tcode{OtherMapping} meets the layout mapping requirements\iref{mdspan.layout.policy.reqmts}. +\constraints +\begin{itemize} +\item +\tcode{\exposid{is-layout-right-padded-mapping-of}} +is \tcode{true}. +\item +\tcode{LayoutRightPaddedMapping::extents_type::rank() == \exposid{rank_}} +is \tcode{true}. +\end{itemize} \pnum \returns -\tcode{true} if \tcode{x.extents() == y.extents()} is \tcode{true}, -\tcode{\exposid{OFFSET}(y) == 0} is \tcode{true}, and -each of \tcode{x.stride($r$) == y.stride($r$)} is \tcode{true} -for $r$ in the range $[0, \tcode{x.extents().rank()})$. +\tcode{true} if \tcode{x.extents() == y.extents()} is \tcode{true} and +\tcode{\exposid{rank_} < 2 || x.stride(\exposid{rank_} - 2) == y.stride(\exposid{rank_} - 2)} is \tcode{true}. Otherwise, \tcode{false}. \end{itemdescr} @@ -20731,7 +24225,7 @@ the accessor policy's \tcode{access} function produces a valid reference to an object. \pnum -In subclause \ref{mdspan.accessor.reqmts}, +In \ref{mdspan.accessor.reqmts}, \begin{itemize} \item @@ -20915,12 +24409,171 @@ an object of type \tcode{default_accessor} if and only if \range{p}{p + $n$} is a valid range. -\rSec5[mdspan.accessor.default.members]{Members} +\rSec5[mdspan.accessor.default.members]{Members} + +\indexlibraryctor{default_accessor}% +\begin{itemdecl} +template + constexpr default_accessor(default_accessor) noexcept {} +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_convertible_v} +is \tcode{true}. +\end{itemdescr} + +\indexlibrarymember{access}{default_accessor}% +\begin{itemdecl} +constexpr reference access(data_handle_type p, size_t i) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return p[i];} +\end{itemdescr} + +\indexlibrarymember{offset}{default_accessor}% +\begin{itemdecl} +constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return p + i;} +\end{itemdescr} + +\rSec4[mdspan.accessor.aligned]{Class template \tcode{aligned_accessor}} + +\rSec5[mdspan.accessor.aligned.overview]{Overview} + +\begin{codeblock} +namespace std { + template + struct @\libglobal{aligned_accessor}@ { + using offset_policy = default_accessor; + using element_type = ElementType; + using reference = ElementType&; + using data_handle_type = ElementType*; + + static constexpr size_t byte_alignment = ByteAlignment; + + constexpr aligned_accessor() noexcept = default; + template + constexpr aligned_accessor( + aligned_accessor) noexcept; + template + constexpr explicit aligned_accessor(default_accessor) noexcept; + + template + constexpr operator default_accessor() const noexcept; + + constexpr reference access(data_handle_type p, size_t i) const noexcept; + + constexpr typename offset_policy::data_handle_type offset( + data_handle_type p, size_t i) const noexcept; + }; +} +\end{codeblock} + +\pnum +\mandates +\begin{itemize} +\item \tcode{byte_alignment} is a power of two, and +\item \tcode{byte_alignment >= alignof(ElementType)} is \tcode{true}. +\end{itemize} + +\pnum +\tcode{aligned_accessor} meets the accessor policy requirements. + +\pnum +\tcode{ElementType} is required to be a complete object type +that is neither an abstract class type nor an array type. + +\pnum +Each specialization of \tcode{aligned_accessor} is +a trivially copyable type that models \libconcept{semiregular}. + +\pnum +\range{0}{$n$} is an accessible range +for an object \tcode{p} of type \tcode{data_handle_type} and +an object of type \tcode{aligned_accessor} if and only if +\begin{itemize} +\item +\range{p}{p + $n$} is a valid range, and, +\item +if $n$ is greater than zero, +then \tcode{is_sufficiently_aligned(p)} is \tcode{true}. +\end{itemize} + +\pnum +\begin{example} +The following function \tcode{compute} +uses \tcode{is_sufficiently_aligned} to check +whether a given \tcode{mdspan} with \tcode{default_accessor} has +a data handle with sufficient alignment +to be used with \tcode{aligned_accessor}. +If so, the function dispatches to +a function \tcode{compute_using_fourfold_overalignment} +that requires fourfold over-alignment of arrays, +but can therefore use hardware-specific instructions, +such as four-wide SIMD (Single Instruction Multiple Data) instructions. +Otherwise, \tcode{compute} dispatches to a +possibly less optimized function \tcode{compute_without_requiring_overalignment} +that has no over-alignment requirement. +\begin{codeblock} +void compute_using_fourfold_overalignment( + std::mdspan, std::layout_right, + std::aligned_accessor> x); + +void compute_without_requiring_overalignment( + std::mdspan, std::layout_right> x); + +void compute(std::mdspan> x) { + constexpr auto byte_alignment = 4 * sizeof(float); + auto accessor = std::aligned_accessor{}; + auto x_handle = x.data_handle(); + + if (std::is_sufficiently_aligned(x_handle)) { + compute_using_fourfold_overalignment(std::mdspan{x_handle, x.mapping(), accessor}); + } else { + compute_without_requiring_overalignment(x); + } +} +\end{codeblock} +\end{example} + +\rSec5[mdspan.accessor.aligned.members]{Members} + +\indexlibraryctor{aligned_accessor}% +\begin{itemdecl} +template + constexpr aligned_accessor(aligned_accessor) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} +is \tcode{true}. +\item +\tcode{OtherByteAlignment >= byte_alignment} is \tcode{true}. +\end{itemize} + +\pnum +\effects +None. +\end{itemdescr} -\indexlibraryctor{default_accessor}% +\indexlibraryctor{aligned_accessor}% \begin{itemdecl} template - constexpr default_accessor(default_accessor) noexcept {} + constexpr explicit aligned_accessor(default_accessor) noexcept; \end{itemdecl} \begin{itemdescr} @@ -20928,28 +24581,58 @@ \constraints \tcode{is_convertible_v} is \tcode{true}. + +\pnum +\effects +None. \end{itemdescr} -\indexlibrarymember{access}{default_accessor}% +\indexlibrarymember{access}{aligned_accessor}% \begin{itemdecl} constexpr reference access(data_handle_type p, size_t i) const noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}. + \pnum \effects -Equivalent to: \tcode{return p[i];} +Equivalent to: \tcode{return assume_aligned(p)[i];} \end{itemdescr} -\indexlibrarymember{offset}{default_accessor}% +\indexlibrarymember{operator default_accessor}{aligned_accessor}% \begin{itemdecl} -constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept; +template + constexpr operator default_accessor() const noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{is_convertible_v} +is \tcode{true}. + \pnum \effects -Equivalent to: \tcode{return p + i;} +Equivalent to: \tcode{return \{\};} +\end{itemdescr} + +\indexlibrarymember{offset}{aligned_accessor}% +\begin{itemdecl} +constexpr typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\range{0}{i + 1} is an accessible range for \tcode{p} and \tcode{*this}. + +\pnum +\effects +Equivalent to: \tcode{return assume_aligned(p) + i;} \end{itemdescr} \rSec3[mdspan.mdspan]{Class template \tcode{mdspan}} @@ -21018,7 +24701,7 @@ constexpr reference operator[](const array& indices) const; constexpr size_type size() const noexcept; - [[nodiscard]] constexpr bool empty() const noexcept; + constexpr bool empty() const noexcept; friend constexpr void swap(mdspan& x, mdspan& y) noexcept; @@ -21039,7 +24722,7 @@ constexpr bool is_exhaustive() const { return @\exposid{map_}@.is_exhaustive(); } constexpr bool is_strided() const - { return @\exposid{map_.}@is_strided(); } + { return @\exposid{map_}@.is_strided(); } constexpr index_type stride(rank_type r) const { return @\exposid{map_}@.stride(r); } @@ -21062,7 +24745,7 @@ template requires ((is_convertible_v && ...) && sizeof...(Integrals) > 0) explicit mdspan(ElementType*, Integrals...) - -> mdspan>; + -> mdspan...>>; template mdspan(ElementType*, span) @@ -21363,17 +25046,16 @@ \pnum \expects -\begin{itemize} -\item -For each rank index \tcode{r} of \tcode{extents_type}, -\tcode{static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r)} -is \tcode{true}. -\item $[0, \tcode{\exposid{map_}.required_span_size()})$ is an accessible range of \exposid{ptr_} and \exposid{acc_} for values of \exposid{ptr_}, \exposid{map_}, and \exposid{acc_} after the invocation of this constructor. -\end{itemize} + +\pnum +\hardexpects +For each rank index \tcode{r} of \tcode{extents_type}, +\tcode{static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r)} +is \tcode{true}. \pnum \effects @@ -21419,7 +25101,7 @@ Let \tcode{I} be \tcode{extents_type::\exposid{index-cast}(std::move(indices))}. \pnum -\expects +\hardexpects \tcode{I} is a multidimensional index in \tcode{extents()}. \begin{note} This implies that @@ -21462,7 +25144,7 @@ is \tcode{true}. Equivalent to: \begin{codeblock} -return operator[](as_const(indices[P])...); +return operator[](extents_type::@\exposid{index-cast}@(as_const(indices[P]))...); \end{codeblock} \end{itemdescr} @@ -21484,7 +25166,7 @@ \indexlibrarymember{empty}{mdspan}% \begin{itemdecl} -[[nodiscard]] constexpr bool empty() const noexcept; +constexpr bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -21511,9 +25193,9 @@ \end{codeblock} \end{itemdescr} -\rSec3[mdspan.submdspan]{\tcode{submdspan}} +\rSec3[mdspan.sub]{\tcode{submdspan}} -\rSec4[mdspan.submdspan.overview]{Overview} +\rSec4[mdspan.sub.overview]{Overview} \pnum The \tcode{submdspan} facilities create a new \tcode{mdspan} @@ -21522,7 +25204,7 @@ the \tcode{SliceSpecifier} arguments. \pnum -For each function defined in subclause \ref{mdspan.submdspan} that +For each function defined in \ref{mdspan.sub} that takes a parameter pack named \tcode{slices} as an argument: \begin{itemize} @@ -21556,7 +25238,7 @@ \end{itemize} \end{itemize} -\rSec4[mdspan.submdspan.strided.slice]{\tcode{strided_slice}} +\rSec4[mdspan.sub.strided.slice]{\tcode{strided_slice}} \pnum \tcode{strided_slice} represents a set of @@ -21595,7 +25277,7 @@ Indices are selected from the half-open interval \range{1}{1 + 10}. \end{note} -\rSec4[mdspan.submdspan.submdspan.mapping.result]{\tcode{submdspan_mapping_result}} +\rSec4[mdspan.sub.map.result]{\tcode{submdspan_mapping_result}} \pnum Specializations of \tcode{submdspan_mapping_result} @@ -21621,7 +25303,7 @@ \tcode{LayoutMapping} shall meet the layout mapping requirements\iref{mdspan.layout.policy.reqmts}. -\rSec4[mdspan.submdspan.helpers]{Exposition-only helpers} +\rSec4[mdspan.sub.helpers]{Exposition-only helpers} \indexlibraryglobal{\exposid{de-ice}}% \indexlibraryglobal{\exposid{first_}}% @@ -21744,7 +25426,7 @@ \end{itemize} \end{itemdescr} -\rSec4[mdspan.submdspan.extents]{\tcode{submdspan_extents} function} +\rSec4[mdspan.sub.extents]{\tcode{submdspan_extents} function} \indexlibraryglobal{submdspan_extents}% \begin{itemdecl} @@ -21851,45 +25533,30 @@ \end{itemize} \end{itemdescr} -\rSec4[mdspan.submdspan.mapping]{Layout specializations of \tcode{submdspan_mapping}} - -\indexlibrarymemberexpos{layout_stride::mapping}{submdspan-mapping-impl}% -\indexlibrarymemberexpos{layout_left::mapping}{submdspan-mapping-impl}% -\indexlibrarymemberexpos{layout_right::mapping}{submdspan-mapping-impl}% -\begin{itemdecl} -template - template - constexpr auto layout_left::mapping::@\exposid{submdspan-mapping-impl}@( // \expos - SliceSpecifiers... slices) const -> @\seebelow@; - -template - template - constexpr auto layout_right::mapping::@\exposid{submdspan-mapping-impl}@( // \expos - SliceSpecifiers... slices) const -> @\seebelow@; +\rSec4[mdspan.sub.map]{Specializations of \tcode{submdspan_mapping}} -template - template - constexpr auto layout_stride::mapping::@\exposid{submdspan-mapping-impl}@( // \expos - SliceSpecifiers... slices) const -> @\seebelow@; -\end{itemdecl} +\rSec5[mdspan.sub.map.common]{Common} -\begin{itemdescr} \pnum -Let \tcode{index_type} be \tcode{typename Extents::index_type}. +The following elements apply to all functions in \ref{mdspan.sub.map}. \pnum \constraints -\tcode{sizeof...(slices)} equals \tcode{Extents::rank()}. +\tcode{sizeof...(slices)} equals \tcode{extents_type::rank()}. \pnum \mandates For each rank index $k$ of \tcode{extents()}, exactly one of the following is true: \begin{itemize} -\item $S_k$ models \tcode{\libconcept{convertible_to}}, -\item $S_k$ models \tcode{\exposconcept{index-pair-like}}, -\item \tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}, or -\item $S_k$ is a specialization of \tcode{strided_slice}. +\item +$S_k$ models \tcode{\libconcept{convertible_to}}, +\item +$S_k$ models \tcode{\exposconcept{index-pair-like}}, +\item +\tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}, or +\item +$S_k$ is a specialization of \tcode{strided_slice}. \end{itemize} \pnum @@ -21898,106 +25565,389 @@ all of the following are \tcode{true}: \begin{itemize} \item -if $S_k$ is a specialization of \tcode{strided_slice} - \begin{itemize} - \item $\tcode{$s_k$.extent} = 0$, or - \item $\tcode{$s_k$.stride} > 0$ - \end{itemize} +if $S_k$ is a specialization of \tcode{strided_slice}, +\tcode{$s_k$.extent} is equal to zero or +\tcode{$s_k$.stride} is greater than zero; and \item -$0 \le \tcode{\exposid{first_}(slices...)} \\ -\hphantom{0 } \le \tcode{\exposid{last_}<$k$>(extents(), slices...)} \\ -\hphantom{0 } \le \tcode{extents().extent($k$)}$ +$0 \leq \tcode{\exposid{first_}(slices...)} \\ +\hphantom{0 } \leq \tcode{\exposid{last_}<$k$>(extents(), slices...)} \\ +\hphantom{0 } \leq \tcode{extents().extent($k$)}$ \end{itemize} \pnum -Let \tcode{sub_ext} be the result of -\tcode{submdspan_extents(extents(), slices...)} and -let \tcode{SubExtents} be \tcode{decltype(sub_ext)}. +Let \tcode{sub_ext} be +the result of \tcode{submdspan_extents(extents(), slices...)} and +let \tcode{SubExtents} be \tcode{decl\-type(sub_ext)}. \pnum Let \tcode{sub_strides} be -an \tcode{array} such that -for each rank index $k$ of \tcode{extents()} -for which \tcode{\placeholder{map-rank}[$k$]} is not \tcode{dynamic_extent}, -\tcode{sub_strides[\placeholder{map-rank}[\linebreak{}$k$]]} equals: - +an \tcode{array} +such that for each rank index $k$ of \tcode{extents()} +for which \tcode{\exposid{map-rank}[$k$]} is not \tcode{dynamic_extent}, +\tcode{sub_strides[\exposid{map-rank}[$k$]]} equals: \begin{itemize} \item -\tcode{stride($k$) * \exposid{de-ice}($s_k$.stride)} +\tcode{stride(k) * \exposid{de-ice}($s_k$.stride)} if $S_k$ is a specialization of \tcode{strided_slice} and -\tcode{$s_k$.stride < $s_k$.extent}; - +\tcode{$s_k$.stride < $s_k$.\linebreak extent} is \tcode{true}; \item -otherwise, -\tcode{stride($k$)}. +otherwise, \tcode{stride($k$)}. \end{itemize} \pnum -Let \tcode{P} be a parameter pack such that -\tcode{is_same_v, index_sequence<\linebreak{}P...>>} +Let \tcode{P} be a parameter pack +such that \tcode{is_same_v, index_sequence>} is \tcode{true}. \pnum -Let \tcode{offset} be a value of type \tcode{size_t} -equal to \tcode{(*this)(\exposid{first_}(slices...)...)}. +If \tcode{\exposid{first_}(slices...)} +equals \tcode{extents().extent($k$)} +for any rank index $k$ of \tcode{extents()}, then +let \tcode{offset} be a value of type \tcode{size_t} equal to +\tcode{(*this).required_span_size()}. +Otherwise, +let \tcode{offset} be a value of type \tcode{size_t} equal to +\tcode{(*this)(\exposid{first_}(slices...)...)}. + +\pnum +Given a layout mapping type \tcode{M}, a type \tcode{S} is a +\defnadjx{unit-stride}{slice for \tcode{M}}{slice} if +\begin{itemize} +\item \tcode{S} is a specialization of \tcode{strided_slice} +where \tcode{S::stride_type} models \exposconcept{integral-constant-like} +and \tcode{S::stride_type::value} equals \tcode{1}, +\item \tcode{S} models \tcode{\exposconcept{index-pair-like}}, or +\item \tcode{is_convertible_v} is \tcode{true}. +\end{itemize} + +\rSec5[mdspan.sub.map.left]{\tcode{layout_left} specialization of \tcode{submdspan_mapping}} + +\indexlibrarymemberexpos{layout_left::mapping}{submdspan-mapping-impl}% +\begin{itemdecl} +template +template +constexpr auto layout_left::mapping::@\exposid{submdspan-mapping-impl}@( + SliceSpecifiers... slices) const -> @\seebelow@; +\end{itemdecl} +\begin{itemdescr} \pnum \returns \begin{itemize} \item \tcode{submdspan_mapping_result\{*this, 0\}}, if \tcode{Extents::rank() == 0} is \tcode{true}; - +\item +otherwise, +\tcode{submdspan_mapping_result\{layout_left::mapping(sub_ext), offset\}}, +if \tcode{SubEx\-tents::rank() == 0} is \tcode{true}; \item otherwise, \tcode{submdspan_mapping_result\{layout_left::mapping(sub_ext), offset\}}, if \begin{itemize} \item - \tcode{layout_type} is \tcode{layout_left}; and - \item for each $k$ in the range \range{0}{SubExtents::rank() - 1)}, \tcode{is_convertible_v<$S_k$, full_ext\-ent_t>} is \tcode{true}; and \item for $k$ equal to \tcode{SubExtents::rank() - 1}, - $S_k$ models \tcode{\exposconcept{index-pair-like}} or - \tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}; + $S_k$ is a unit-stride slice for \tcode{mapping}; \end{itemize} \begin{note} If the above conditions are true, all $S_k$ with $k$ larger than \tcode{SubExtents::rank() - 1} are convertible to \tcode{index_type}. \end{note} +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_left_padded::mapping(sub_ext, stride(@$u$@ + 1)), + offset} +\end{codeblock} +if for a value $u$ for which $u+1$ is +the smallest value $p$ larger than zero +for which $S_p$ is a unit-stride slice for \tcode{mapping}, +the following conditions are met: +\begin{itemize} +\item +$S_0$ is a unit-stride slice for \tcode{mapping}; and +\item +for each $k$ in the range \range{$u$ + 1}{$u$ + SubExtents::rank() - 1}, +\tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}; and +\item +for $k$ equal to \tcode{$u$ + SubExtents::rank() - 1}, +$S_k$ is a unit-stride slice for \tcode{mapping}; +\end{itemize} +and where \tcode{S_static} is: +\begin{itemize} +\item +\tcode{dynamic_extent}, +if \tcode{static_extent($k$)} is \tcode{dynamic_extent} +for any $k$ in the range \range{0}{$u$ + 1}, +\item +otherwise, the product of all values +\tcode{static_extent($k$)} for $k$ in the range \range{0}{$u$ + 1}; +\end{itemize} +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset} +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec5[mdspan.sub.map.right]{\tcode{layout_right} specialization of \tcode{submdspan_mapping}} + +\indexlibrarymemberexpos{layout_right::mapping}{submdspan-mapping-impl}% +\begin{itemdecl} +template +template +constexpr auto layout_right::mapping::@\exposid{submdspan-mapping-impl}@( + SliceSpecifiers... slices) const -> @\seebelow@; +\end{itemdecl} +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item +\tcode{submdspan_mapping_result\{*this, 0\}}, +if \tcode{Extents::rank() == 0} is \tcode{true}; \item otherwise, \tcode{submdspan_mapping_result\{layout_right::mapping(sub_ext), offset\}}, +if \tcode{Sub\-Extents::rank() == 0} is \tcode{true}; +\item +otherwise, +\tcode{submdspan_mapping_result\{layout_left::mapping(sub_ext), offset\}}, if \begin{itemize} \item - \tcode{layout_type} is \tcode{layout_right}; and - \item - for each $k$ in the range - \range{Extents::rank() - SubExtents::rank() + 1}{Extents::rank()}, + for each $k$ in the range \range{\exposid{rank_} - SubExtents::rank() + 1}{\exposid{rank_}}, \tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}; and \item - for $k$ equal to \tcode{Extents::rank() - SubExtents::rank()}, - $S_k$ models \tcode{\exposconcept{index-pair-like}} or - \tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}; + for $k$ equal to \exposid{_rank} - \tcode{SubExtents::rank()}, + $S_k$ is a unit-stride slice for \tcode{mapping}; \end{itemize} \begin{note} If the above conditions are true, -all $S_k$ with $k < \tcode{Extents::rank() - SubExtents::rank()}$ +all $S_k$ with $k < \tcode{\exposid{_rank} - SubExtents::rank()}$ are convertible to \tcode{index_type}. \end{note} +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_right_padded::mapping(sub_ext, + stride(@\exposid{rank_}@ - @$u$@ - 2)), offset} +\end{codeblock} +if for a value $u$ for which $\exposid{rank_} - u - 2$ is +the largest value $p$ smaller than \tcode{\exposid{rank_} - 1} +for which $S_p$ is a unit-stride slice for \tcode{mapping}, +the following conditions are met: +\begin{itemize} +\item +for $k$ equal to \tcode{\exposid{rank_} - 1}, +$S_k$ is a unit-stride slice for \tcode{mapping}; and +\item +for each $k$ in the range +\range{\exposid{rank_} - SubExtents::rank() - $u$ + 1}{\exposid{rank_} - $u$ - 1}, +\tcode{is_con\-vertible_v<$S_k$, full_extent_t>} is \tcode{true}; and +\item +for $k$ equal to \tcode{\exposid{rank_} - SubExtents::rank() - $u$},\newline +$S_k$ is a unit-stride slice for \tcode{mapping}; +\end{itemize} +and where \tcode{S_static} is: +\begin{itemize} +\item +\tcode{dynamic_extent}, +if \tcode{static_extent($k$)} is \tcode{dynamic_extent} +for any $k$ in the range \range{\exposid{rank_} - $u$ - 1}{\exposid{rank_}}, +\item +otherwise, the product of all values +\tcode{static_extent($k$)} +for $k$ in the range \range{\exposid{rank_} - $u$ - 1}{\exposid{rank_}}; +\end{itemize} +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset} +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec5[mdspan.sub.map.stride]{\tcode{layout_stride} specialization of \tcode{submdspan_mapping}} + +\indexlibrarymemberexpos{layout_stride::mapping}{submdspan-mapping-impl}% +\begin{itemdecl} +template +template +constexpr auto layout_stride::mapping::@\exposid{submdspan-mapping-impl}@( + SliceSpecifiers... slices) const -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item +\tcode{submdspan_mapping_result\{*this, 0\}}, +if \tcode{Extents::rank() == 0} is \tcode{true}; +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset} +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec5[mdspan.sub.map.leftpad]{\tcode{layout_left_padded} specialization of \tcode{submdspan_mapping}} + +\indexlibrarymemberexpos{layout_left_padded::mapping}{submdspan-mapping-impl}% +\begin{itemdecl} +template +template +constexpr auto layout_left_padded::mapping::@\exposid{submdspan-mapping-impl}@( + SliceSpecifiers... slices) const -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item +\tcode{submdspan_mapping_result\{*this, 0\}}, +if \tcode{Extents::rank() == 0} is \tcode{true}; +\item +otherwise, +\tcode{submdspan_mapping_result\{layout_left::mapping(sub_ext), offset\}}, +if \tcode{\exposid{rank_} == 1} is \tcode{true} or +\tcode{SubExtents::rank() == 0} is \tcode{true}; +\item +otherwise, +\tcode{submdspan_mapping_result\{layout_left::mapping(sub_ext), offset\}}, +if +\begin{itemize} +\item +\tcode{SubExtents::rank() == 1} is \tcode{true} and +\item +$S_0$ is a unit-stride slice for \tcode{mapping}; +\end{itemize} +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_left_padded::mapping(sub_ext, stride(@$u$@ + 1)), + offset} +\end{codeblock} +if for a value $u$ +for which \tcode{$u$ + 1} is the smallest value $p$ larger than zero +for which $S_p$ is a unit-stride slice for \tcode{mapping}, +the following conditions are met: +\begin{itemize} +\item +$S_0$ is a unit-stride slice for \tcode{mapping}; and +\item +for each $k$ in the range \range{$u$ + 1}{$u$ + SubExtents::rank() - 1}, +\tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}; and +\item +for $k$ equal to \tcode{$u$ + SubExtents::rank() - 1}, +$S_k$ is a unit-stride slice for \tcode{mapping}; +\end{itemize} +where \tcode{S_static} is: +\begin{itemize} +\item +\tcode{dynamic_extent}, +if \exposid{static-padding-stride} is \tcode{dynamic_extent} or +\tcode{static_extent($k$)} is \tcode{dynamic_extent} +for any $k$ in the range \range{1}{$u$ + 1}, +\item +otherwise, the product of \exposid{static-padding-stride} and +all values \tcode{static_extent($k$)} for $k$ in the range \range{1}{$u$ + 1}; +\end{itemize} +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset} +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec5[mdspan.sub.map.rightpad]{\tcode{layout_right_padded} specialization of \tcode{submdspan_mapping}} + +\indexlibrarymemberexpos{layout_right_padded::mapping}{submdspan-mapping-impl}% +\begin{itemdecl} +template +template +constexpr auto layout_right_padded::mapping::submdspan-mapping-impl( + SliceSpecifiers... slices) const -> @\seebelow@; +\end{itemdecl} +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item +\tcode{submdspan_mapping_result\{*this, 0\}}, +if \tcode{\exposid{rank_} == 0} is \tcode{true}; +\item +otherwise, +\tcode{submdspan_mapping_result\{layout_right::mapping(sub_ext), offset\}},\newline +if \tcode{\exposid{rank_} == 1} is \tcode{true} or +\tcode{SubExtents::rank() == 0} is \tcode{true}; +\item +otherwise, +\tcode{submdspan_mapping_result\{layout_right::mapping(sub_ext), offset\}}, +if +\begin{itemize} +\item +\tcode{SubExtents::rank() == 1} is \tcode{true} and +\item +for $k$ equal to \tcode{\exposid{rank_} - 1}, +$S_k$ is a unit-stride slice for \tcode{mapping}; +\end{itemize} +\item +otherwise, +\begin{codeblock} +submdspan_mapping_result{layout_right_padded::mapping(sub_ext, + stride(@\exposid{rank_}@ - @$u$@ - 2)), offset} +\end{codeblock} +if for a value $u$ +for which \tcode{\exposid{rank_} - $u$ - 2} +is the largest value p smaller than \tcode{\exposid{rank_} - 1} +for which $S_p$ is a unit-stride slice for \tcode{mapping}, +the following conditions are met: +\begin{itemize} +\item +for $k$ equal to \tcode{\exposid{rank_} - 1}, +$S_k$ is a unit-stride slice for \tcode{mapping}; and +\item +for each $k$ in the range +\range{\exposid{rank_} - SubExtents::rank() - $u$ + 1}{\exposid{rank_} - $u$ - 1)}, +\tcode{is_convertible_v<$S_k$, full_extent_t>} is \tcode{true}; and +\item +for $k$ equal to \tcode{\exposid{rank_} - SubExtents::rank() - $u$},\newline +$S_k$ is a unit-stride slice for \tcode{mapping}; +\end{itemize} +and where \tcode{S_static} is: +\begin{itemize} +\item +\tcode{dynamic_extent} +if \exposid{static-padding-stride} is \tcode{dynamic_extent} or +for any $k$ in the range \range{\exposid{rank_} - $u$ - 1}{\exposid{rank_} - 1} +\tcode{static_extent($k$)} is \tcode{dynamic_extent}, +\item +otherwise, the product of \exposid{static-padding-stride} and +all values \tcode{static_extent($k$)} +with $k$ in the range \range{\exposid{rank_} - $u$ - 1}{\exposid{rank_} - 1}; +\end{itemize} \item otherwise, -\tcode{submdspan_mapping_result\{layout_stride::mapping(sub_ext, sub_strides),\linebreak{}offset\}}. +\begin{codeblock} +submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset} +\end{codeblock} \end{itemize} \end{itemdescr} -\rSec4[mdspan.submdspan.submdspan]{\tcode{submdspan} function template} +\rSec4[mdspan.sub.sub]{\tcode{submdspan} function template} \indexlibraryglobal{submdspan}% \begin{itemdecl} @@ -22097,9 +26047,9 @@ \effects Equivalent to: \begin{codeblock} -auto sub_map_offset = submdspan_mapping(src.mapping(), slices...); -return mdspan(src.accessor().offset(src.data(), sub_map_offset.offset), - sub_map_offset.mapping, +auto sub_map_result = submdspan_mapping(src.mapping(), slices...); +return mdspan(src.accessor().offset(src.data(), sub_map_result.offset), + sub_map_result.mapping, AccessorPolicy::offset_policy(src.accessor())); \end{codeblock} \end{itemdescr} diff --git a/source/cover-reg.tex b/source/cover-reg.tex index 91e968e150..5923fce26d 100644 --- a/source/cover-reg.tex +++ b/source/cover-reg.tex @@ -59,15 +59,16 @@ \thispagestyle{cpppage} -\fbox{% -\begin{minipage}{\copyboxwidth} +\vspace*{\fill} + \vspace{1ex} -\begin{center} -\textbf{Copyright notice} -\end{center} +\raisebox{-1ex}{\includegraphics{assets/iso-logo-caution.png}}\qquad{\Large{\textbf{COPYRIGHT PROTECTED DOCUMENT}}} \vspace{2ex} +\isocopyright + All rights reserved. Unless otherwise specified, +or required in the context of its implementation, no part of this publication may be reproduced or utilized otherwise in any form or by any means, electronic or mechanical, including photocopying, @@ -75,17 +76,18 @@ without prior written permission. Permission can be requested from either ISO at the address below -or ISO's member body in the country of the requester.\\\\ +or ISO's member body in the country of the requester. \begin{indented} \microtypesetup{activate=false}% ISO copyright office\\ -Case postale 56, CH-1211 Geneva 20\\ -\rlap{Tel.}\hphantom{Fax} + 41 22 749 01 11\\ -Fax + 41 22 749 09 47\\ -E-mail \texttt{copyright@iso.org}\\ -Web \url{www.iso.org} +CP 401 \textbullet{} Ch.\ de Blandonnet 8\\ +CH-1214 Vernier, Geneva\\ +Phone: +41 22 749 01 11\\ +Email: \texttt{copyright@iso.org}\\ +Website: \url{www.iso.org} \end{indented} -\end{minipage}} + +Published in Switzerland \newpage diff --git a/source/declarations.tex b/source/declarations.tex index 929bd6a027..020161723b 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -1,5 +1,5 @@ %!TEX root = std.tex -\rSec0[dcl.dcl]{Declarations}% +\rSec0[dcl]{Declarations}% \indextext{declaration|(} \gramSec[gram.dcl]{Declarations} @@ -13,8 +13,7 @@ the form \begin{bnf} \nontermdef{declaration-seq}\br - declaration\br - declaration-seq declaration + declaration \opt{declaration-seq} \end{bnf} \begin{bnf} @@ -28,6 +27,7 @@ block-declaration\br nodeclspec-function-declaration\br function-definition\br + friend-type-declaration\br template-declaration\br deduction-guide\br linkage-specification\br @@ -67,17 +67,33 @@ \keyword{using} identifier \opt{attribute-specifier-seq} \terminal{=} defining-type-id \terminal{;} \end{bnf} +\begin{bnf} +\nontermdef{sb-identifier}\br + \opt{\terminal{...}} identifier \opt{attribute-specifier-seq} +\end{bnf} + +\begin{bnf} +\nontermdef{sb-identifier-list}\br + sb-identifier\br + sb-identifier-list \terminal{,} sb-identifier +\end{bnf} + +\begin{bnf} +\nontermdef{structured-binding-declaration}\br + \opt{attribute-specifier-seq} decl-specifier-seq \opt{ref-qualifier} \terminal{[} sb-identifier-list \terminal{]} +\end{bnf} + \begin{bnf} \nontermdef{simple-declaration}\br decl-specifier-seq \opt{init-declarator-list} \terminal{;}\br attribute-specifier-seq decl-specifier-seq init-declarator-list \terminal{;}\br - \opt{attribute-specifier-seq} decl-specifier-seq \opt{ref-qualifier} \terminal{[} identifier-list \terminal{]} initializer \terminal{;} + structured-binding-declaration initializer \terminal{;} \end{bnf} \begin{bnf} \nontermdef{static_assert-message}\br unevaluated-string\br - conditional-expression + constant-expression \end{bnf} \begin{bnf} @@ -112,11 +128,16 @@ \indextext{scope}% Certain declarations contain one or more scopes\iref{basic.scope.scope}. Unless otherwise stated, utterances in -\ref{dcl.dcl} about components in, of, or contained by a +\ref{dcl} about components in, of, or contained by a declaration or subcomponent thereof refer only to those components of the declaration that are \emph{not} nested within scopes nested within the declaration. +\pnum +If a \grammarterm{name-declaration} matches +the syntactic requirements of \grammarterm{friend-type-declaration}, +it is a \grammarterm{friend-type-declaration}. + \pnum A \grammarterm{simple-declaration} or @@ -186,14 +207,21 @@ \end{example} \pnum -A \grammarterm{simple-declaration} with an \grammarterm{identifier-list} is called +A \grammarterm{simple-declaration} or a \grammarterm{condition} +with a \grammarterm{structured-binding-declaration} is called a \defn{structured binding declaration}\iref{dcl.struct.bind}. Each \grammarterm{decl-specifier} in the \grammarterm{decl-specifier-seq} shall be +\tcode{constexpr}, +\tcode{constinit}, \tcode{static}, \tcode{thread_local}, \tcode{auto}\iref{dcl.spec.auto}, or a \grammarterm{cv-qualifier}. +The declaration shall contain at most one \grammarterm{sb-identifier} +whose \grammarterm{identifier} is preceded by an ellipsis. +If the declaration contains any such \grammarterm{sb-identifier}, +it shall declare a templated entity\iref{temp.pre}. \begin{example} \begin{codeblock} template concept C = true; @@ -205,9 +233,13 @@ of the form ``\tcode{=} \grammarterm{assignment-expression}'', of the form ``\tcode{\{} \grammarterm{assignment-expression} \tcode{\}}'', or -of the form ``\tcode{(} \grammarterm{assignment-expression} \tcode{)}'', -where the -\grammarterm{assignment-expression} is of array or non-union class type. +of the form ``\tcode{(} \grammarterm{assignment-expression} \tcode{)}''. +If the \grammarterm{structured-binding-declaration} appears as +a \grammarterm{condition}, +the \grammarterm{assignment-expression} shall be of non-union class type. +Otherwise, +the \grammarterm{assignment-expression} shall be of +array or non-union class type. \pnum If the \grammarterm{decl-specifier-seq} contains the \keyword{typedef} @@ -234,16 +266,29 @@ \end{codeblock} \end{example} +\pnum +\indextext{initialization!definition and}% +An object definition causes +storage of appropriate size and alignment to be reserved and +any appropriate initialization\iref{dcl.init} to be done. + \pnum \indextext{definition!declaration as}% Syntactic components beyond those found in the general form of \grammarterm{simple-declaration} are added to a function declaration to make a -\grammarterm{function-definition}. An object declaration, however, is also -a definition unless it contains the \keyword{extern} specifier and has no -initializer\iref{basic.def}. -\indextext{initialization!definition and}% -An object definition causes storage of appropriate size and alignment to be reserved and -any appropriate initialization\iref{dcl.init} to be done. +\grammarterm{function-definition}. +A token sequence starting with \tcode{\{} or \tcode{=} +is treated as a \grammarterm{function-body}\iref{dcl.fct.def.general} +if the type of the \grammarterm{declarator-id}\iref{dcl.meaning.general} +is a function type, and +is otherwise +treated as a \grammarterm{brace-or-equal-initializer}\iref{dcl.init.general}. +\begin{note} +If the declaration acquires a function type through template instantiation, +the program is ill-formed; see \ref{temp.spec.general}. +The function type of a function definition +cannot be specified with a \grammarterm{typedef-name}\iref{dcl.fct}. +\end{note} \pnum A \grammarterm{nodeclspec-function-declaration} shall declare a @@ -291,7 +336,7 @@ the program is ill-formed, and \item if the \grammarterm{static_assert-message} is -a \grammarterm{conditional-expression} $M$, +a \grammarterm{constant-expression} $M$, \begin{itemize} \item \tcode{$M$.size()} shall be a converted constant expression of @@ -378,9 +423,9 @@ same type. \pnum -Each \grammarterm{decl-specifier} -shall appear at most once in a complete \grammarterm{decl-specifier-seq}, -except that \tcode{long} may appear twice. +At most one of each of the \grammarterm{decl-specifier}s +\keyword{friend}, \keyword{typedef}, or \keyword{inline} +shall 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}. @@ -611,6 +656,9 @@ A \grammarterm{function-specifier} can be used only in a function declaration. +At most one \grammarterm{explicit-specifier} and +at most one \keyword{virtual} keyword shall appear in +a \grammarterm{decl-specifier-seq}. \begin{bnf} \nontermdef{function-specifier}\br @@ -730,7 +778,7 @@ \indextext{class name!\idxcode{typedef}}% A \grammarterm{simple-template-id} is only a \grammarterm{typedef-name} if its \grammarterm{template-name} names -an alias template or a template \grammarterm{template-parameter}. +an alias template or a type template template parameter. \begin{note} A \grammarterm{simple-template-id} that names a class template specialization is a \grammarterm{class-name}\iref{class.name}. @@ -807,12 +855,14 @@ \pnum The \keyword{constexpr} specifier shall be applied only to -the definition of a variable or variable template or +the definition of a variable or variable template, +a structured binding declaration, or the declaration of a function or function template. The \keyword{consteval} specifier shall be applied only to the declaration of a function or function template. A function or static data member declared with the \keyword{constexpr} or \keyword{consteval} specifier +on its first declaration is implicitly an inline function or variable\iref{dcl.inline}. If any declaration of a function or function template has a \keyword{constexpr} or \keyword{consteval} specifier, @@ -865,7 +915,7 @@ \pnum \indextext{specifier!\idxcode{constexpr}!function}% \indextext{constexpr function}% -A function is \defn{constexpr-suitable} if: +A function is \defn{constexpr-suitable} if \begin{itemize} \item it is not a coroutine\iref{dcl.fct.def.coroutine}, and @@ -951,9 +1001,7 @@ Such an object shall have literal type and shall be initialized. -In any \keyword{constexpr} variable declaration, -the full-expression of the initialization -shall be a constant expression\iref{expr.const}. +A \keyword{constexpr} variable shall be constant-initializable\iref{expr.const}. A \keyword{constexpr} variable that is an object, as well as any temporary to which a \keyword{constexpr} reference is bound, shall have constant destruction. @@ -964,6 +1012,16 @@ }; constexpr pixel ur = { 1294, 1024 }; // OK constexpr pixel origin; // error: initializer missing + +namespace N { + void f() { + int x; + constexpr int& ar = x; // OK + static constexpr int& sr = x; // error: \tcode{x} is not constexpr-representable + // at the point indicated below + } + // immediate scope here is that of \tcode{N} +} \end{codeblock} \end{example} @@ -972,7 +1030,12 @@ \pnum The \keyword{constinit} specifier shall be applied only -to a declaration of a variable with static or thread storage duration. +to a declaration of a variable with static or thread storage duration +or to a structured binding declaration\iref{dcl.struct.bind}. +\begin{note} +A structured binding declaration introduces a uniquely named variable, +to which the \tcode{constinit} specifier applies. +\end{note} 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 @@ -1214,7 +1277,7 @@ \pnum \indextext{const object!undefined change to}% -Any attempt to modify\iref{expr.ass,expr.post.incr,expr.pre.incr} a +Any attempt to modify\iref{expr.assign,expr.post.incr,expr.pre.incr} a const object\iref{basic.type.qualifier} during its lifetime\iref{basic.life} results in undefined behavior. \begin{example} @@ -1267,10 +1330,10 @@ \indextext{\idxcode{volatile}!implementation-defined}% \begin{note} \tcode{volatile} is a hint to the implementation to avoid aggressive -optimization involving the object because the value of the object might -be changed by means undetectable by an implementation. -Furthermore, for some implementations, \tcode{volatile} might indicate that -special hardware instructions are required to access the object. +optimization involving the object because it is possible for the value of the object +to change by means undetectable by an implementation. +Furthermore, for some implementations, \tcode{volatile} can indicate that +special hardware instructions are needed to access the object. See~\ref{intro.execution} for detailed semantics. In general, the semantics of \tcode{volatile} are intended to be the same in \Cpp{} as they are in C. @@ -1285,7 +1348,7 @@ \nontermdef{simple-type-specifier}\br \opt{nested-name-specifier} type-name\br nested-name-specifier \keyword{template} simple-template-id\br - decltype-specifier\br + computed-type-specifier\br placeholder-type-specifier\br \opt{nested-name-specifier} template-name\br \keyword{char}\br @@ -1311,6 +1374,12 @@ typedef-name \end{bnf} +\begin{bnf} +\nontermdef{computed-type-specifier}\br + decltype-specifier\br + pack-index-specifier +\end{bnf} + \pnum \indextext{component name} The component names of a \grammarterm{simple-type-specifier} are those of its @@ -1382,6 +1451,7 @@ \grammarterm{type-name} & the type named \\ \grammarterm{simple-template-id} & the type as defined in~\ref{temp.names}\\ \grammarterm{decltype-specifier} & the type as defined in~\ref{dcl.type.decltype}\\ +\grammarterm{pack-index-specifier} & the type as defined in~\ref{dcl.type.pack.index}\\ \grammarterm{placeholder-type-specifier} & the type as defined in~\ref{dcl.spec.auto}\\ \grammarterm{template-name} & the type as defined in~\ref{dcl.type.class.deduct}\\ @@ -1431,6 +1501,32 @@ forces \tcode{char} objects to be signed; it is redundant in other contexts. \end{note} +\rSec3[dcl.type.pack.index]{Pack indexing specifier} + +\begin{bnf} +\nontermdef{pack-index-specifier}\br + typedef-name \terminal{...} \terminal{[} constant-expression \terminal{]} +\end{bnf} + +\pnum +The \grammarterm{typedef-name} $P$ in a \grammarterm{pack-index-specifier} +shall denote a pack. + +\pnum +The \grammarterm{constant-expression} shall be +a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +whose value $V$, termed the index, +is such that $0 \le V < \tcode{sizeof...($P$)}$. + +\pnum +A \grammarterm{pack-index-specifier} is a pack expansion\iref{temp.variadic}. + +\pnum +\begin{note} +The \grammarterm{pack-index-specifier} denotes +the type of the $V^\text{th}$ element of the pack. +\end{note} + \rSec3[dcl.type.elab]{Elaborated type specifiers}% \indextext{type specifier!elaborated}% \indextext{\idxcode{typename}}% @@ -1456,8 +1552,10 @@ \indextext{name!elaborated!\idxcode{enum}}% If an \grammarterm{elaborated-type-specifier} is the sole constituent of a declaration, the declaration is ill-formed unless it is an explicit -specialization\iref{temp.expl.spec}, an explicit -instantiation\iref{temp.explicit} or it has one of the following +specialization\iref{temp.expl.spec}, +a partial specialization\iref{temp.spec.partial}, +an explicit +instantiation\iref{temp.explicit}, or it has one of the following forms: \begin{ncsimplebnf} @@ -1471,7 +1569,7 @@ The second case shall appear only in an \grammarterm{explicit-specialization}\iref{temp.expl.spec} or in a \grammarterm{template-declaration} -(where it declares a partial specialization\iref{temp.decls}). +(where it declares a partial specialization). The \grammarterm{attribute-specifier-seq}, if any, appertains to the class or template being declared. @@ -1486,30 +1584,34 @@ The target scope of $E$ is the nearest enclosing namespace or block scope. \pnum -If an \grammarterm{elaborated-type-specifier} appears with -the \keyword{friend} specifier as an entire \grammarterm{member-declaration}, -the \grammarterm{member-declaration} shall have one of the following forms: +A \grammarterm{friend-type-specifier} +that is an \grammarterm{elaborated-type-specifier} +shall have one of the following forms: \begin{ncsimplebnf} -\keyword{friend} class-key \opt{nested-name-specifier} identifier \terminal{;}\br -\keyword{friend} class-key simple-template-id \terminal{;}\br -\keyword{friend} class-key nested-name-specifier \opt{\keyword{template}} simple-template-id \terminal{;} +class-key \opt{nested-name-specifier} identifier\br +class-key simple-template-id\br +class-key nested-name-specifier \opt{\keyword{template}} simple-template-id \end{ncsimplebnf} Any unqualified lookup for the \grammarterm{identifier} (in the first case) -does not consider scopes that contain the target scope; no name is bound. +does not consider scopes that contain +the nearest enclosing namespace or block scope; no name is bound. \begin{note} A \grammarterm{using-directive} in the target scope is ignored if it refers to a namespace not contained by that scope. -\ref{basic.lookup.elab} describes how name lookup proceeds -in an \grammarterm{elaborated-type-specifier}. \end{note} \pnum \begin{note} +\ref{basic.lookup.elab} describes how name lookup proceeds +in an \grammarterm{elaborated-type-specifier}. An \grammarterm{elaborated-type-specifier} can be used to refer to a previously declared \grammarterm{class-name} or \grammarterm{enum-name} even if the name has been hidden by a non-type declaration. \end{note} + +\pnum If the \grammarterm{identifier} or \grammarterm{simple-template-id} +in an \grammarterm{elaborated-type-specifier} resolves to a \grammarterm{class-name} or \grammarterm{enum-name}, the \grammarterm{elaborated-type-specifier} introduces it into the declaration the same way a @@ -1524,12 +1626,12 @@ \begin{codeblock} friend class T; \end{codeblock} -is ill-formed. However, the similar declaration \tcode{friend T;} is allowed\iref{class.friend}. +is ill-formed. However, the similar declaration \tcode{friend T;} is well-formed\iref{class.friend}. \end{note} \pnum The \grammarterm{class-key} or \keyword{enum} keyword -present in the +present in an \grammarterm{elaborated-type-specifier} shall agree in kind with the declaration to which the name in the \grammarterm{elaborated-type-specifier} refers. This rule also applies to @@ -1569,8 +1671,8 @@ the specification of the structured binding declaration; \item otherwise, if $E$ is an unparenthesized \grammarterm{id-expression} -naming a non-type \grammarterm{template-parameter}\iref{temp.param}, -\tcode{decltype($E$)} is the type of the \grammarterm{template-parameter} +naming a constant template parameter\iref{temp.param}, +\tcode{decltype($E$)} is the type of the template parameter after performing any necessary type deduction\iref{dcl.spec.auto,dcl.type.class.deduct}; @@ -1604,6 +1706,13 @@ decltype(i) x2; // type is \tcode{int} decltype(a->x) x3; // type is \tcode{double} decltype((a->x)) x4 = x3; // type is \tcode{const double\&} + +void f() { + [](auto ...pack) { + decltype(pack...[0]) x5; // type is \tcode{int} + decltype((pack...[0])) x6; // type is \tcode{int\&} + }(0); +} \end{codeblock} \end{example} \begin{note} @@ -1675,20 +1784,33 @@ \pnum A \grammarterm{placeholder-type-specifier} -designates a placeholder type that will be replaced later by deduction +designates a placeholder type that will be replaced later, +typically by deduction from an initializer. \pnum -A \grammarterm{placeholder-type-specifier} of the form -\opt{\grammarterm{type-constraint}} \keyword{auto} -can be used as a \grammarterm{decl-specifier} of -the \grammarterm{decl-specifier-seq} of -a \grammarterm{parameter-declaration} of -a function declaration or \grammarterm{lambda-expression} and, -if it is not the \keyword{auto} \grammarterm{type-specifier} -introducing a \grammarterm{trailing-return-type} (see below), +The type of a \grammarterm{parameter-declaration} of a +\begin{itemize} + \item function declaration\iref{dcl.fct}, + \item \grammarterm{lambda-expression}\iref{expr.prim.lambda}, or + \item \grammarterm{template-parameter}\iref{temp.param} +\end{itemize} +can be declared using +a \grammarterm{placeholder-type-specifier} of the form +\opt{\grammarterm{type-constraint}} \keyword{auto}. +The placeholder type shall appear +as one of the \grammarterm{decl-specifier}{s} in +the \grammarterm{decl-specifier-seq} or +as one of the \grammarterm{type-specifier}{s} in +a \grammarterm{trailing-return-type} +that specifies the type that replaces such +a \grammarterm{decl-specifier} (see below); +the placeholder type is a \defn{generic parameter type placeholder} -of the function declaration or \grammarterm{lambda-expression}. +of the +function declaration, +\grammarterm{lambda-expression}, or +\grammarterm{template-parameter}, respectively. \begin{note} Having a generic parameter type placeholder signifies that the function is @@ -1697,15 +1819,15 @@ \end{note} \pnum -A placeholder type can appear with a function declarator in the -\grammarterm{decl-specifier-seq}, \grammarterm{type-specifier-seq}, -\grammarterm{conversion-function-id}, or \grammarterm{trailing-return-type}, -in any context where such a declarator is valid. If the function declarator -includes a \grammarterm{trailing-return-type}\iref{dcl.fct}, that -\grammarterm{trailing-return-type} specifies -the declared return type of the function. Otherwise, the function declarator -shall declare a function. If the declared return type of the -function contains a placeholder type, the return type of the function is +A placeholder type can appear in +the \grammarterm{decl-specifier-seq} for a function declarator +that includes a \grammarterm{trailing-return-type}\iref{dcl.fct}. + +\pnum +A placeholder type can appear in +the \grammarterm{decl-specifier-seq} or \grammarterm{type-specifier-seq} +in the declared return type of a function declarator that declares a function; +the return type of the function is deduced from non-discarded \tcode{return} statements, if any, in the body of the function\iref{stmt.if}. @@ -1715,9 +1837,11 @@ This use is allowed in an initializing declaration\iref{dcl.init} of a variable. The placeholder type shall appear as one of the -\grammarterm{decl-specifier}{s} in the -\grammarterm{decl-specifier-seq} and the -\grammarterm{decl-specifier-seq} +\grammarterm{decl-specifier}{s} in the \grammarterm{decl-specifier-seq} +or as one of the +\grammarterm{type-specifier}{s} in a \grammarterm{trailing-return-type} +that specifies the type that replaces such a \grammarterm{decl-specifier}; +the \grammarterm{decl-specifier-seq} shall be followed by one or more \grammarterm{declarator}{s}, each of which shall @@ -1731,6 +1855,7 @@ auto int r; // error: \keyword{auto} is not a \grammarterm{storage-class-specifier} auto f() -> int; // OK, \tcode{f} returns \tcode{int} auto g() { return 0.0; } // OK, \tcode{g} returns \tcode{double} +auto (*fp)() -> auto = f; // OK auto h(); // OK, \tcode{h}'s return type will be deduced when it is defined \end{codeblock} \end{example} @@ -1740,13 +1865,19 @@ \pnum A placeholder type can also be used -in the \grammarterm{type-specifier-seq} in -the \grammarterm{new-type-id} or \grammarterm{type-id} of a -\grammarterm{new-expression}\iref{expr.new} -and as a \grammarterm{decl-specifier} -of the \grammarterm{parameter-declaration}{'s} -\grammarterm{decl-specifier-seq} -in a \grammarterm{template-parameter}\iref{temp.param}. +in the \grammarterm{type-specifier-seq} of +the \grammarterm{new-type-id} or +in the \grammarterm{type-id} of a +\grammarterm{new-expression}\iref{expr.new}. +In such a \grammarterm{type-id}, +the placeholder type shall appear +as one of the \grammarterm{type-specifier}{s} in +the \grammarterm{type-specifier-seq} or +as one of the \grammarterm{type-specifier}{s} in +a \grammarterm{trailing-return-type} +that specifies the type that replaces such a \grammarterm{type-specifier}. + +\pnum The \tcode{auto} \grammarterm{type-specifier} can also be used as the \grammarterm{simple-type-specifier} in an explicit type conversion (functional notation)\iref{expr.type.conv}. @@ -1819,6 +1950,20 @@ \end{codeblock} \end{example} +\pnum +A result binding never has +an undeduced placeholder type\iref{dcl.contract.res}. +\begin{example} +\begin{codeblock} +auto f() + post(r : r == 7) // OK +{ + return 7; +} +\end{codeblock} +\end{example} + + \pnum Return type deduction for a templated function with a placeholder in its @@ -1975,9 +2120,9 @@ and $E$ is the \grammarterm{assignment-expression}. \end{itemize} \item -For a non-type template parameter declared with a type +For a constant template parameter declared with a type that contains a placeholder type, -\tcode{T} is the declared type of the non-type template parameter +\tcode{T} is the declared type of the constant template parameter and $E$ is the corresponding template argument. \end{itemize} @@ -2151,8 +2296,8 @@ \begin{bnf} \nontermdef{init-declarator}\br - declarator \opt{initializer}\br - declarator requires-clause + declarator initializer\br + declarator \opt{requires-clause} \opt{function-contract-specifier-seq} \end{bnf} \pnum @@ -2244,6 +2389,12 @@ \end{codeblock} \end{example} +\pnum +The optional \grammarterm{function-contract-specifier-seq}\iref{dcl.contract.func} +in an \grammarterm{init-declarator} +shall be present only if +the \grammarterm{declarator} declares a function. + \pnum Declarators have the syntax @@ -2279,7 +2430,7 @@ \end{bnf} \begin{bnf} -\microtypesetup{protrusion=false}\obeyspaces +\microtypesetup{protrusion=false} \nontermdef{ptr-operator}\br \terminal{*} \opt{attribute-specifier-seq} \opt{cv-qualifier-seq}\br \terminal{\&} \opt{attribute-specifier-seq}\br @@ -2366,7 +2517,6 @@ \begin{bnf} \nontermdef{noptr-abstract-pack-declarator}\br noptr-abstract-pack-declarator parameters-and-qualifiers\br - noptr-abstract-pack-declarator \terminal{[} \opt{constant-expression} \terminal{]} \opt{attribute-specifier-seq}\br \terminal{...} \end{bnf} @@ -2877,7 +3027,7 @@ \end{example} \pnum -See also~\ref{expr.ass} and~\ref{dcl.init}. +See also~\ref{expr.assign} and~\ref{dcl.init}. \pnum \begin{note} @@ -3029,16 +3179,46 @@ specifier\iref{dcl.stc}, is a class member\iref{class.mem} declaration within a class definition, or is the declaration of a parameter or a return type\iref{dcl.fct}; see~\ref{basic.def}. -A reference shall be initialized to refer to a valid object or function. + +\pnum +Attempting to bind a reference to a function where +the converted initializer is a glvalue whose +type is not call-compatible\iref{expr.call} +with the type of the function's definition +results in undefined behavior. +Attempting to bind a reference to an object where +the converted initializer is a glvalue through which +the object is not type-accessible\iref{basic.lval} +results in undefined behavior. \begin{note} \indextext{reference!null}% -In particular, a null reference cannot exist in a well-defined program, -because the only way to create such a reference would be to bind it to -the ``object'' obtained by indirection through a null pointer, -which causes undefined behavior. +The object designated by such a glvalue can be +outside its lifetime\iref{basic.life}. +Because a null pointer value or a pointer past the end of an object +does not point to an object, +a reference in a well-defined program cannot refer to such things; +see~\ref{expr.unary.op}. As described in~\ref{class.bit}, a reference cannot be bound directly to a bit-field. \end{note} +The behavior of an evaluation of a reference\iref{expr.prim.id, expr.ref} that +does not happen after\iref{intro.races} the initialization of the reference +is undefined. +\begin{example} +\begin{codeblock} +int &f(int&); +int &g(); +extern int &ir3; +int *ip = 0; +int &ir1 = *ip; // undefined behavior: null pointer +int &ir2 = f(ir3); // undefined behavior: \tcode{ir3} not yet initialized +int &ir3 = g(); +int &ir4 = f(ir4); // undefined behavior: \tcode{ir4} used in its own initializer + +char x alignas(int); +int &ir5 = *reinterpret_cast(&x); // undefined behavior: initializer refers to char object +\end{codeblock} +\end{example} \pnum \indextext{reference collapsing}% @@ -3396,60 +3576,44 @@ \tcode{T} \tcode{D} where +\tcode{T} may be empty and \tcode{D} has the form \begin{ncsimplebnf} \terminal{D1} \terminal{(} parameter-declaration-clause \terminal{)} \opt{cv-qualifier-seq}\br -\bnfindent\opt{ref-qualifier} \opt{noexcept-specifier} \opt{attribute-specifier-seq} +\bnfindent\opt{ref-qualifier} \opt{noexcept-specifier} \opt{attribute-specifier-seq} \opt{trailing-return-type} \end{ncsimplebnf} -and the type of the contained +a \placeholder{derived-declarator-type-list} is determined as follows: +\begin{itemize} +\item +If the \grammarterm{unqualified-id} of the \grammarterm{declarator-id} +is a \grammarterm{conversion-function-id}, +the \placeholder{derived-declarator-type-list} is empty. + +\item +Otherwise, the \placeholder{derived-declarator-type-list} is as appears in +the type ``\placeholder{derived-declarator-type-list} \tcode{T}'' +of the contained \grammarterm{declarator-id} in the declaration \tcode{T} -\tcode{D1} -is -``\placeholder{derived-declarator-type-list} -\tcode{T}'', -the type of the -\grammarterm{declarator-id} -in -\tcode{D} -is -``\placeholder{derived-declarator-type-list} -\opt{\keyword{noexcept}} -function of parameter-type-list -\opt{\grammarterm{cv-qualifier-seq}} \opt{\grammarterm{ref-qualifier}} -returning \tcode{T}'', where +\tcode{D1}. +\end{itemize} +The declared return type \tcode{U} of the function type +is determined as follows: \begin{itemize} \item -the parameter-type-list is derived from -the \grammarterm{parameter-declaration-clause} as described below and +If the \grammarterm{trailing-return-type} is present, +\tcode{T} shall be the single \grammarterm{type-specifier} \keyword{auto}, and +\tcode{U} is the type specified by the \grammarterm{trailing-return-type}. + \item -the optional \keyword{noexcept} is present if and only if -the exception specification\iref{except.spec} is non-throwing. -\end{itemize} -The optional \grammarterm{attribute-specifier-seq} -appertains to the function type. +Otherwise, if the declaration declares a conversion function, +see~\ref{class.conv.fct}. -\pnum -In a declaration -\tcode{T} -\tcode{D} -where -\tcode{D} -has the form -\begin{ncsimplebnf} -\terminal{D1} \terminal{(} parameter-declaration-clause \terminal{)} \opt{cv-qualifier-seq}\br -\bnfindent\opt{ref-qualifier} \opt{noexcept-specifier} \opt{attribute-specifier-seq} trailing-return-type -\end{ncsimplebnf} -and the type of the contained -\grammarterm{declarator-id} -in the declaration -\tcode{T} -\tcode{D1} -is -``\placeholder{derived-declarator-type-list} \tcode{T}'', -\tcode{T} shall be the single \grammarterm{type-specifier} \keyword{auto}. +\item +Otherwise, \tcode{U} is \tcode{T}. +\end{itemize} The type of the \grammarterm{declarator-id} in @@ -3463,28 +3627,26 @@ \begin{itemize} \item the parameter-type-list is derived from -the \grammarterm{parameter-declaration-clause} as described below, -\item -\tcode{U} is the type specified by the \grammarterm{trailing-return-type}, and +the \grammarterm{parameter-declaration-clause} as described below and \item the optional \keyword{noexcept} is present if and only if -the exception specification is non-throwing. +the exception specification\iref{except.spec} is non-throwing. \end{itemize} -The optional \grammarterm{attribute-specifier-seq} -appertains to the function type. - -\pnum -\indextext{type!function}% -A type of either form is a \term{function type}.% +Such a type is a \defnadj{function}{type}. \begin{footnote} As indicated by syntax, cv-qualifiers are a significant component in function return types. \end{footnote} +The optional \grammarterm{attribute-specifier-seq} +appertains to the function type. +\pnum \indextext{declaration!function}% \begin{bnf} \nontermdef{parameter-declaration-clause}\br - \opt{parameter-declaration-list} \opt{\terminal{...}}\br - parameter-declaration-list \terminal{,} \terminal{...} + \terminal{...}\br + \opt{parameter-declaration-list}\br + parameter-declaration-list \terminal{,} \terminal{...}\br + parameter-declaration-list \terminal{...} \end{bnf} \begin{bnf} @@ -3520,7 +3682,7 @@ If the \grammarterm{parameter-declaration-clause} is empty, the function takes no arguments. -A parameter list consisting of a single unnamed parameter of +A parameter list consisting of a single unnamed non-object parameter of non-dependent type \keyword{void} is equivalent to an empty parameter list. \indextext{parameter!\idxcode{void}}% @@ -3540,9 +3702,13 @@ argument and are not function parameter packs. Where syntactically correct and where ``\tcode{...}'' is not part of an \grammarterm{abstract-declarator}, -``\tcode{, ...}'' +``\tcode{...}'' is synonymous with -``\tcode{...}''. +``\tcode{, ...}''. +A \grammarterm{parameter-declaration-clause} +of the form +\grammarterm{parameter-declaration-list} \tcode{...} +is deprecated\iref{depr.ellipsis.comma}. \begin{example} The declaration \begin{codeblock} @@ -3612,11 +3778,15 @@ a \grammarterm{parameter-declaration} with a \keyword{this} specifier. An explicit-object-parameter-declaration shall appear only as the first \grammarterm{parameter-declaration} of -a \grammarterm{parameter-declaration-list} of either: +a \grammarterm{parameter-declaration-list} of one of: \begin{itemize} \item -a \grammarterm{member-declarator} -that declares a member function\iref{class.mem}, or +a declaration of +a member function or member function template\iref{class.mem}, or +\item +an explicit instantiation\iref{temp.explicit} or +explicit specialization\iref{temp.expl.spec} of +a templated member function, or \item a \grammarterm{lambda-declarator}\iref{expr.prim.lambda}. \end{itemize} @@ -3871,7 +4041,7 @@ An abbreviated function template is equivalent to a function template\iref{temp.fct} whose \grammarterm{template-parameter-list} includes -one invented type \grammarterm{template-parameter} +one invented \grammarterm{type-parameter} for each generic parameter type placeholder of the function declaration, in order of appearance. For a \grammarterm{placeholder-type-specifier} of the form \keyword{auto}, @@ -3881,7 +4051,7 @@ \grammarterm{type-constraint} \keyword{auto}, the invented parameter is a \grammarterm{type-parameter} with that \grammarterm{type-constraint}. -The invented type \grammarterm{template-parameter} is +The invented \grammarterm{type-parameter} declares a template parameter pack if the corresponding \grammarterm{parameter-declaration} declares a function parameter pack. @@ -3890,7 +4060,7 @@ The adjusted function parameters of an abbreviated function template are derived from the \grammarterm{parameter-declaration-clause} by replacing each occurrence of a placeholder with -the name of the corresponding invented \grammarterm{template-parameter}. +the name of the corresponding invented \grammarterm{type-parameter}. \begin{example} \begin{codeblock} template concept C1 = /* ... */; @@ -3918,7 +4088,7 @@ \pnum An abbreviated function template can have a \grammarterm{template-head}. -The invented \grammarterm{template-parameter}{s} are +The invented \grammarterm{type-parameter}{s} are appended to the \grammarterm{template-parameter-list} after the explicitly declared \grammarterm{template-parameter}{s}. \begin{example} @@ -4026,9 +4196,7 @@ of a function declaration or \grammarterm{lambda-declarator} or in a -\grammarterm{template-parameter}\iref{temp.param}; -in the latter case, the \grammarterm{initializer-clause} shall be an -\grammarterm{assignment-expression}. +\grammarterm{template-parameter}\iref{temp.param}. A default argument shall not be specified for a template parameter pack or a function parameter pack. @@ -4301,6 +4469,326 @@ \indextext{declaration!default argument|)}% \indextext{declarator!meaning of|)} +\rSec1[dcl.contract]{Function contract specifiers} +\rSec2[dcl.contract.func]{General} + +\indextext{contract assertion!function|(}% + +\begin{bnf} +\nontermdef{function-contract-specifier-seq}\br + function-contract-specifier \opt{function-contract-specifier-seq} +\end{bnf} + +\begin{bnf} +\nontermdef{function-contract-specifier}\br + precondition-specifier\br + postcondition-specifier +\end{bnf} + +\begin{bnf} +\nontermdef{precondition-specifier}\br + \terminal{pre} \opt{attribute-specifier-seq} \terminal{(} conditional-expression \terminal{)} +\end{bnf} + +\begin{bnf} +\nontermdef{postcondition-specifier}\br + \terminal{post} \opt{attribute-specifier-seq} \terminal{(} \opt{result-name-introducer} conditional-expression \terminal{)} +\end{bnf} + +\pnum +\indexdefn{contract assertion!postcondition|see{assertion, postcondition}} +\indexdefn{contract assertion!precondition|see{assertion, precondition}} +A \defnadj{function}{contract assertion} +is a contract assertion\iref{basic.contract.general} +associated with a function. +A \grammarterm{precondition-specifier} +introduces a \defnadj{precondition}{assertion}, +which is a function contract assertion +associated with entering a function. +A \grammarterm{postcondition-specifier} +introduces a \defnadj{postcondition}{assertion}, +which is a function contract assertion +associated with exiting a function normally. +\begin{note} +A postcondition assertion +is not associated with exiting a function +in any other fashion, +such as via an exception\iref{expr.throw} +or via a call to \tcode{longjmp}\iref{csetjmp.syn}. +\end{note} + +\pnum +The predicate\iref{basic.contract.general} +of a function contract assertion +is its \grammarterm{conditional-expression} +contextually converted to \tcode{bool}. + +\pnum +Each \grammarterm{function-contract-specifier} +of a \grammarterm{function-contract-specifier-seq} (if any) +of an unspecified first declaration\iref{basic.def} +of a function +introduces a corresponding function contract assertion for that function. +The optional \grammarterm{attribute-specifier-seq} +following \tcode{pre} or \tcode{post} +appertains to the introduced contract assertion. +\begin{note} +The \grammarterm{function-contract-specifier-seq} +of a \grammarterm{lambda-declarator} +applies to the function call operator or operator template +of the corresponding closure type\iref{expr.prim.lambda.closure}. +\end{note} + +\pnum +A declaration $D$ +of a function or function template \placeholder{f} +that is not a first declaration shall have either +no \grammarterm{function-contract-specifier-seq} +or the same \grammarterm{function-contract-specifier-seq} (see below) +as any first declaration $F$ reachable from $D$. +If $D$ and $F$ are +in different translation units, +a diagnostic is required only if $D$ is attached to a named module. +If a declaration $F_1$ is a +first declaration of \tcode{f} +in one translation unit and +a declaration $F_2$ is a +first declaration of \tcode{f} in another translation unit, +$F_1$ and $F_2$ shall specify the same +\grammarterm{function-contract-specifier-seq}, no diagnostic required. + +\pnum +A \grammarterm{function-contract-specifier-seq} $S_1$ +is the same as +a \grammarterm{function-contract-specifier-seq} $S_2$ +if $S_1$ and $S_2$ consist of +the same \grammarterm{function-contract-specifier}s +in the same order. +A \grammarterm{function-contract-specifier} $C_1$ +on a function declaration $D_1$ is +the same as +a \grammarterm{function-contract-specifier} $C_2$ +on a function declaration $D_2$ +if +\begin{itemize} +\item +their predicates $P_1$ and $P_2$ would +satisfy the one-definition rule\iref{basic.def.odr} +if placed in function definitions on +the declarations $D_1$ and $D_2$, respectively, except for +\begin{itemize} +\item +renaming of the parameters of \placeholder{f}, +\item +renaming of template parameters of +a template enclosing \placeholder{}, and +\item +renaming of the result binding\iref{dcl.contract.res}, if any, +\end{itemize} +and, +if $D_1$ and $D_2$ are in different translation units, +corresponding entities defined within each predicate +behave as if there is a single entity with a single definition, and +\item +both $C_1$ and $C_2$ +specify a \grammarterm{result-name-introducer} +or neither do. +\end{itemize} +If this condition is not met +solely due to the comparison of two \grammarterm{lambda-expression}s +that are contained within $P_1$ and $P_2$, +no diagnostic is required. + +\begin{note} +Equivalent +\grammarterm{function-contract-specifier-seq}s +apply to all uses and definitions +of a function across all translation units. +\end{note} +\begin{example} +\begin{codeblock} + +bool b1, b2; + +void f() pre (b1) pre ([]{ return b2; }()); +void f(); // OK, \grammarterm{function-contract-specifier}s omitted +void f() pre (b1) pre ([]{ return b2; }()); // error: closures have different types. +void f() pre (b1); // error: \grammarterm{function-contract-specifier}s only partially repeated + +int g() post(r : b1); +int g() post(b1); // error: mismatched \grammarterm{result-name-introducer} presence + +namespace N { + void h() pre (b1); + bool b1; + void h() pre (b1); // error: \grammarterm{function-contract-specifier}s differ according to + // the one-definition rule\iref{basic.def.odr}. +} +\end{codeblock} +\end{example} + +\pnum +A virtual function\iref{class.virtual}, +a deleted function\iref{dcl.fct.def.delete}, +or a function defaulted on its first declaration\iref{dcl.fct.def.default} +shall not have a \grammarterm{function-contract-specifier-seq}. + +\pnum +If the predicate of a postcondition assertion +of a function \placeholder{f} +odr-uses\iref{basic.def.odr} +a non-reference parameter of \placeholder{f}, +that parameter +and the corresponding parameter on all declarations of \placeholder{f} +shall have \keyword{const} type. +\begin{note} +This requirement applies +even to declarations that do not specify the \grammarterm{postcondition-specifier}. +Parameters with array or function type +will decay to non-\keyword{const} types +even if a \keyword{const} qualifier is present. +\begin{example} +\begin{codeblock} +int f(const int i[10]) + post(r : r == i[0]); // error: \tcode{i} has type \tcode{const int *} (not \tcode{int* const}). +\end{codeblock} +\end{example} +\end{note} + +\pnum +\begin{note} +The function contract assertions of a function +are evaluated even when invoked indirectly, +such as through a pointer to function or a pointer to member function. +A pointer to function, +pointer to member function, +or function type alias +cannot have a \grammarterm{function-contract-specifier-seq} +associated directly with it. +\end{note} + +\pnum +The function contract assertions of a function +are considered to be \defnx{needed}{needed!function contract assertion}\iref{temp.inst} when +\begin{itemize} +\item +the function is odr-used\iref{basic.def.odr} or +\item +the function is defined. +\end{itemize} +\begin{note} +Overload resolution does not consider +\grammarterm{function-contract-specifier}s\iref{temp.deduct,temp.inst}. +\begin{example} +\begin{codeblock} +template void f(T t) pre( t == "" ); +template void f(T&& t); +void g() +{ + f(5); // error: ambiguous +} +\end{codeblock} +\end{example} +\end{note} + + +\rSec2[dcl.contract.res]{Referring to the result object} + +\begin{bnf} +\nontermdef{attributed-identifier}\br + identifier \opt{attribute-specifier-seq} +\end{bnf} + +\begin{bnf} +\nontermdef{result-name-introducer}\br + attributed-identifier \terminal{:} +\end{bnf} + +\pnum +The \grammarterm{result-name-introducer} +of a \grammarterm{postcondition-specifier} +is a declaration. +The \grammarterm{result-name-introducer} +introduces the \grammarterm{identifier} +as the name of a \defn{result binding} +of the associated function. +If a postcondition assertion has a \grammarterm{result-name-introducer} +and the return type of the function is \cv{} \keyword{void}, +the program is ill-formed. +A result binding denotes +the object or reference returned by +invocation of that function. +The type of a result binding +is the return type of its associated function +The optional \grammarterm{attribute-specifier-seq} +of the \grammarterm{attributed-identifier} +in the \grammarterm{result-name-introducer} +appertains to the result binding so introduced. +\begin{note} +An \grammarterm{id-expression} +that names a result binding is a \keyword{const} lvalue\iref{expr.prim.id.unqual}. +\end{note} + +\begin{example} +\begin{codeblock} +int f() + post(r : r == 1) +{ + return 1; +} +int i = f(); // Postcondition check succeeds. +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +struct A {}; +struct B { + B() {} + B(const B&) {} +}; + +template +T f(T* const ptr) + post(r: &r == ptr) +{ + return {}; +} + +int main() { + A a = f(&a); // The postcondition check can fail if the implementation introduces + // a temporary for the return value\iref{class.temporary}. + B b = f(&b); // The postcondition check succeeds, no temporary is introduced. +} +\end{codeblock} +\end{example} + + +\pnum +When the declared return type +of a non-templated function +contains a placeholder type, +a \grammarterm{postcondition-specifier} +with a \grammarterm{result-name-introducer} +shall be present only on a definition. +\begin{example} +\begin{codeblock} +auto g(auto&) + post (r: r >= 0); // OK, \tcode{g} is a template. + +auto h() + post (r: r >= 0); // error: cannot name the return value + +auto k() + post (r: r >= 0) // OK +{ + return 0; +} +\end{codeblock} +\end{example} + +\indextext{contract assertion!function|)}% + \rSec1[dcl.init]{Initializers}% \rSec2[dcl.init.general]{General}% @@ -4481,7 +4969,10 @@ \item If \tcode{T} -is an array type, each element is default-initialized. +is an array type, +the semantic constraints of default-initializing a hypothetical element +shall be met and +each element is default-initialized. \item Otherwise, @@ -4520,29 +5011,27 @@ an object of type \tcode{T} means: + \begin{itemize} \item -if +If \tcode{T} is a (possibly cv-qualified) class type\iref{class}, then -\begin{itemize} -\item -if \tcode{T} has -either no default constructor\iref{class.default.ctor} or a default -constructor that is user-provided or deleted, then the object is default-initialized; -\item -otherwise, -the object is zero-initialized and the semantic constraints for -default-initialization are checked, and if \tcode{T} has a -non-trivial default constructor, the object is default-initialized; -\end{itemize} +let \tcode{C} be the constructor selected to +default-initialize the object, if any. +If \tcode{C} is not user-provided, the object is first zero-initialized. +In all cases, the object is then default-initialized. + \item -if +If \tcode{T} -is an array type, then each element is value-initialized; +is an array type, +the semantic constraints of value-initializing a hypothetical element +shall be met and +each element is value-initialized. \item -otherwise, the object is zero-initialized. +Otherwise, the object is zero-initialized. \end{itemize} \pnum @@ -4553,7 +5042,7 @@ \pnum \begin{note} -For every object of static storage duration, +For every object with static storage duration, static initialization\iref{basic.start.static} is performed at program startup before any other initialization takes place. In some cases, additional initialization is done later. @@ -4602,7 +5091,7 @@ The \indextext{type!destination}% \term{destination type} -is the type of the object or reference being initialized and the +is the cv-unqualified type of the object or reference being initialized and the \term{source type} is the type of the initializer expression. If the initializer is not a single (possibly parenthesized) expression, the @@ -4638,13 +5127,15 @@ \tcode{X}. The form \tcode{()} -is permitted in certain other initialization contexts\iref{expr.new, +can appear in certain other initialization contexts\iref{expr.new, expr.type.conv,class.base.init}. \end{note} \item Otherwise, if the destination type is an array, the object is initialized as follows. +The \grammarterm{initializer} shall be of the form +\tcode{(} \grammarterm{expression-list} \tcode{)}. Let $x_1$, $\dotsc$, $x_k$ be the elements of the \grammarterm{expression-list}. If the destination type is an array of unknown bound, @@ -4661,13 +5152,13 @@ is sequenced before those associated with the initialization of the $j^\text{th}$ element. \item -Otherwise, if the destination type is a (possibly cv-qualified) class type: +Otherwise, if the destination type is a class type: \begin{itemize} \item If the initializer expression is a prvalue and the cv-unqualified version of the source type -is the same class as the class of the destination, +is the same as the destination type, the initializer expression is used to initialize the destination object. \begin{example} \tcode{T x = T(T(T()));} value-initializes \tcode{x}. @@ -4675,7 +5166,7 @@ \item Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source -type is the same class as, or a derived class of, the class of the destination, +type is the same as or is derived from the class of the destination type, constructors are considered. The applicable constructors are enumerated\iref{over.match.ctor}, and the best one is chosen @@ -4706,7 +5197,7 @@ is sequenced before those associated with the initialization of $e_j$. \begin{note} By contrast with direct-list-initialization, -narrowing conversions\iref{dcl.init.list} are permitted, +narrowing conversions\iref{dcl.init.list} can appear, designators are not permitted, a temporary object bound to a reference does not have its lifetime extended\iref{class.temporary}, and @@ -4772,7 +5263,7 @@ the (possibly converted) value of the initializer expression. A standard conversion sequence\iref{conv} is used to convert the initializer expression to -a prvalue of the cv-unqualified version of +a prvalue of the destination type; no user-defined conversions are considered. If the conversion cannot @@ -4914,8 +5405,8 @@ \item If the initializer list is a brace-enclosed \grammarterm{initializer-list}, the explicitly initialized elements of the aggregate -are the first $n$ elements of the aggregate, -where $n$ is the number of elements in the initializer list. +are those for which an element of the initializer list +appertains to the aggregate element or to a subobject thereof (see below). \item Otherwise, the initializer list must be \tcode{\{\}}, and there are no explicitly initialized elements. @@ -4946,21 +5437,30 @@ initializes \tcode{c.a} with 1 and \tcode{c.x} with 3. \end{example} \item -Otherwise, the element is copy-initialized -from the corresponding \grammarterm{initializer-clause} -or is initialized with the \grammarterm{brace-or-equal-initializer} +Otherwise, if the initializer list is +a brace-enclosed \grammarterm{designated-initializer-list}, +the element is initialized with the \grammarterm{brace-or-equal-initializer} of the corresponding \grammarterm{designated-initializer-clause}. If that initializer is of the form -\grammarterm{assignment-expression} or \tcode{= }\grammarterm{assignment-expression} and a narrowing conversion\iref{dcl.init.list} is required to convert the expression, the program is ill-formed. \begin{note} -If the initialization is by \grammarterm{designated-initializer-clause}, -its form determines whether copy-initialization or direct-initialization -is performed. +The form of the initializer determines +whether copy-initialization or direct-initialization is performed. \end{note} +\item +Otherwise, +the initializer list is a brace-enclosed \grammarterm{initializer-list}. +If an \grammarterm{initializer-clause} appertains to the aggregate element, +then the aggregate element is copy-initialized from the \grammarterm{initializer-clause}. +Otherwise, +the aggregate element is copy-initialized +from a brace-enclosed \grammarterm{initializer-list} +consisting of all of the \grammarterm{initializer-clause}s +that appertain to subobjects of the aggregate element, +in the order of appearance. \begin{note} If an initializer is itself an initializer list, the element is list-initialized, which will result in a recursive application @@ -5050,13 +5550,7 @@ with the value of an expression of the form \tcode{int\{\}} (that is, \tcode{0}), and \tcode{ss.d} with the value of \tcode{ss.b[ss.a]} -(that is, \tcode{'s'}), and in -\begin{codeblock} -struct X { int i, j, k = 42; }; -X a[] = { 1, 2, 3, 4, 5, 6 }; -X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } }; -\end{codeblock} -\tcode{a} and \tcode{b} have the same value +(that is, \tcode{'s'}). \begin{codeblock} struct A { @@ -5088,6 +5582,7 @@ \pnum The destructor for each element of class type +other than an anonymous union member is potentially invoked\iref{class.dtor} from the context where the aggregate initialization occurs. \begin{note} @@ -5097,15 +5592,9 @@ \end{note} \pnum -An array of unknown bound initialized with a -brace-enclosed -\grammarterm{initializer-list} -containing -\tcode{n} -\grammarterm{initializer-clause}{s} -is defined as having -\tcode{n} -elements\iref{dcl.array}. +The number of elements\iref{dcl.array} in an array of unknown bound +initialized with a brace-enclosed \grammarterm{initializer-list} +is the number of explicitly initialized elements of the array. \begin{example} \begin{codeblock} int x[] = { 1, 3, 5 }; @@ -5115,6 +5604,15 @@ as a one-dimensional array that has three elements since no size was specified and there are three initializers. \end{example} +\begin{example} +In +\begin{codeblock} +struct X { int i, j, k; }; +X a[] = { 1, 2, 3, 4, 5, 6 }; +X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } }; +\end{codeblock} +\tcode{a} and \tcode{b} have the same value. +\end{example} An array of unknown bound shall not be initialized with an empty \grammarterm{braced-init-list} \tcode{\{\}}. \begin{footnote} @@ -5162,19 +5660,6 @@ \end{example} \end{note} -\pnum -An -\grammarterm{initializer-list} -is ill-formed if the number of -\grammarterm{initializer-clause}{s} -exceeds the number of elements of the aggregate. -\begin{example} -\begin{codeblock} -char cv[4] = { 'a', 's', 'd', 'f', 0 }; // error -\end{codeblock} -is ill-formed. -\end{example} - \pnum If a member has a default member initializer and a potentially-evaluated subexpression thereof is an aggregate @@ -5196,32 +5681,6 @@ \end{codeblock} \end{example} -\pnum -If an aggregate class \tcode{C} contains a subaggregate element -\tcode{e} with no elements, -the \grammarterm{initializer-clause} for \tcode{e} shall not be -omitted from an \grammarterm{initializer-list} for an object of type -\tcode{C} unless the \grammarterm{initializer-clause}{s} for all -elements of \tcode{C} following \tcode{e} are also omitted. -\begin{example} -\begin{codeblock} -struct S { } s; -struct A { - S s1; - int i1; - S s2; - int i2; - S s3; - int i3; -} a = { - { }, // Required initialization - 0, - s, // Required initialization - 0 -}; // Initialization not required for \tcode{A::s3} because \tcode{A::i3} is also not initialized -\end{codeblock} -\end{example} - \pnum When initializing a multidimensional array, the @@ -5259,28 +5718,71 @@ \end{example} \pnum -Braces can be elided in an -\grammarterm{initializer-list} -as follows. -If the -\grammarterm{initializer-list} -begins with a left brace, -then the succeeding comma-separated list of -\grammarterm{initializer-clause}{s} -initializes the elements of a subaggregate; -it is erroneous for there to be more -\grammarterm{initializer-clause}{s} -than elements. -If, however, the -\grammarterm{initializer-list} -for a subaggregate does not begin with a left brace, -then only enough -\grammarterm{initializer-clause}{s} -from the list are taken to initialize the elements of the subaggregate; -any remaining -\grammarterm{initializer-clause}{s} -are left to initialize the next element of the aggregate -of which the current subaggregate is an element. +Each \grammarterm{initializer-clause} in +a brace-enclosed \grammarterm{initializer-list} +is said to \defn{appertain} +to an element of the aggregate being initialized or +to an element of one of its subaggregates. +Considering the sequence of \grammarterm{initializer-clause}s, +and the sequence of aggregate elements +initially formed as the sequence of elements of the aggregate being initialized +and potentially modified as described below, +each \grammarterm{initializer-clause} appertains to +the corresponding aggregate element if +\begin{itemize} +\item +the aggregate element is not an aggregate, or +\item +the \grammarterm{initializer-clause} begins with a left brace, or +\item +the \grammarterm{initializer-clause} is an expression and +an implicit conversion sequence can be formed +that converts the expression to the type of the aggregate element, or +\item +the aggregate element is an aggregate that itself has no aggregate elements. +\end{itemize} +Otherwise, +the aggregate element is an aggregate and +that subaggregate is replaced in the list of aggregate elements by +the sequence of its own aggregate elements, and +the appertainment analysis resumes with +the first such element and the same \grammarterm{initializer-clause}. +\begin{note} +These rules apply recursively to the aggregate's subaggregates. +\begin{example} +In +\begin{codeblock} +struct S1 { int a, b; }; +struct S2 { S1 s, t; }; + +S2 x[2] = { 1, 2, 3, 4, 5, 6, 7, 8 }; +S2 y[2] = { + { + { 1, 2 }, + { 3, 4 } + }, + { + { 5, 6 }, + { 7, 8 } + } +}; +\end{codeblock} +\tcode{x} and \tcode{y} have the same value. +\end{example} +\end{note} +This process continues +until all \grammarterm{initializer-clause}s have been exhausted. +If any \grammarterm{initializer-clause} remains +that does not appertain to +an element of the aggregate or one of its subaggregates, +the program is ill-formed. +\begin{example} +\begin{codeblock} +char cv[4] = { 'a', 's', 'd', 'f', 0 }; // error: too many initializers +\end{codeblock} +\end{example} + +\pnum \begin{example} \begin{codeblock} float y[4][3] = { @@ -5335,22 +5837,30 @@ \end{example} \pnum -All implicit type conversions\iref{conv} are considered when -initializing the element with an \grammarterm{assignment-expression}. -If the -\grammarterm{assignment-expression} -can initialize an element, the element is initialized. -Otherwise, if the element is itself a subaggregate, -brace elision is assumed and the -\grammarterm{assignment-expression} -is considered for the initialization of the first element of the subaggregate. \begin{note} -As specified above, brace elision cannot apply to -subaggregates with no elements; an -\grammarterm{initializer-clause} for the entire subobject is -required. +The initializer for an empty subaggregate is needed +if any initializers are provided for subsequent elements. +\begin{example} +\begin{codeblock} +struct S { } s; +struct A { + S s1; + int i1; + S s2; + int i2; + S s3; + int i3; +} a = { + { }, // Required initialization + 0, + s, // Required initialization + 0 +}; // Initialization not required for \tcode{A::s3} because \tcode{A::i3} is also not initialized +\end{codeblock} +\end{example} \end{note} +\pnum \begin{example} \begin{codeblock} struct A { @@ -5364,7 +5874,6 @@ A a; B b = { 4, a, a }; \end{codeblock} - Braces are elided around the \grammarterm{initializer-clause} for @@ -5515,7 +6024,7 @@ A reference cannot be changed to refer to another object after initialization. \indextext{assignment!reference}% \begin{note} -Assignment to a reference assigns to the object referred to by the reference\iref{expr.ass}. +Assignment to a reference assigns to the object referred to by the reference\iref{expr.assign}. \end{note} \indextext{argument passing!reference and}% Argument passing\iref{expr.call} @@ -5620,13 +6129,14 @@ \item Otherwise, if the initializer expression \begin{itemize} -\item is an rvalue (but not a bit-field) or function lvalue and +\item is an rvalue (but not a bit-field) or an lvalue of function type and ``\cvqual{cv1} \tcode{T1}'' is reference-compatible with ``\cvqual{cv2} \tcode{T2}'', or \item has a class type (i.e., \tcode{T2} is a class type), where \tcode{T1} is not reference-related to \tcode{T2}, and can be converted to -an rvalue or function lvalue of type ``\cvqual{cv3} \tcode{T3}'', +an rvalue of type ``\cvqual{cv3} \tcode{T3}'' or +an lvalue of function type ``\cvqual{cv3} \tcode{T3}'', where ``\cvqual{cv1} \tcode{T1}'' is reference-compatible with ``\cvqual{cv3} \tcode{T3}'' (see~\ref{over.match.ref}), \end{itemize} @@ -5635,8 +6145,10 @@ the converted expression in the second case is called the converted initializer. If the converted initializer is a prvalue, -its type \tcode{T4} is adjusted to type ``\cvqual{cv1} \tcode{T4}''\iref{conv.qual} -and the temporary materialization conversion\iref{conv.rval} is applied. +let its type be denoted by \tcode{T4}; +the temporary materialization conversion\iref{conv.rval} is applied, +considering the type of the prvalue to be +``\cvqual{cv1} \tcode{T4}''\iref{conv.qual}. In any case, the reference binds to the resulting glvalue (or to an appropriate base class subobject). @@ -5656,15 +6168,25 @@ int i2 = 42; int&& rri = static_cast(i2); // binds directly to \tcode{i2} B&& rrb = x; // binds directly to the result of \tcode{operator B} + +constexpr int f() { + const int &x = 42; + const_cast(x) = 1; // undefined behavior + return x; +} +constexpr int z = f(); // error: not a constant expression + +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} +ACPC &&r = AP{}; // binds directly \end{codeblock} \end{example} \item -Otherwise: +Otherwise, \tcode{T1} shall not be reference-related to \tcode{T2}. \begin{itemize} \item -If \tcode{T1} or \tcode{T2} is a class type and -\tcode{T1} is not reference-related to \tcode{T2}, +If \tcode{T1} or \tcode{T2} is a class type, user-defined conversions are considered using the rules for copy-initialization of an object of type ``\cvqual{cv1} \tcode{T1}'' by @@ -5683,24 +6205,6 @@ and the reference is bound to the result. \end{itemize} -If -\tcode{T1} -is reference-related to -\tcode{T2}: -\begin{itemize} -\item -\cvqual{cv1} -shall be the same cv-qualification as, or greater cv-qualification than, -\cvqual{cv2}; and -\item -if the reference is an rvalue reference, -the initializer expression shall not be an lvalue. -\begin{note} -This can be affected by -whether the initializer expression is move-eligible\iref{expr.prim.id.unqual}. -\end{note} -\end{itemize} - \begin{example} \begin{codeblock} struct Banana { }; @@ -5713,7 +6217,7 @@ Banana &&banana3 = Alaska(); // error } -const double& rcd2 = 2; // \tcode{rcd2} refers to temporary with value \tcode{2.0} +const double& rcd2 = 2; // \tcode{rcd2} refers to temporary with type \tcode{const double} and value \tcode{2.0} double&& rrd = 2; // \tcode{rrd} refers to temporary with value \tcode{2.0} const volatile int cvi = 1; const int& r2 = cvi; // error: cv-qualifier dropped @@ -5765,16 +6269,17 @@ \begin{note} List-initialization can be used \begin{itemize} -\item as the initializer in a variable definition\iref{dcl.init} -\item as the initializer in a \grammarterm{new-expression}\iref{expr.new} -\item in a \tcode{return} statement\iref{stmt.return} -\item as a \grammarterm{for-range-initializer}\iref{stmt.iter} -\item as a function argument\iref{expr.call} -\item as a subscript\iref{expr.sub} -\item as an argument to a constructor invocation\iref{dcl.init,expr.type.conv} -\item as an initializer for a non-static data member\iref{class.mem} -\item in a \grammarterm{mem-initializer}\iref{class.base.init} -\item on the right-hand side of an assignment\iref{expr.ass} +\item as the initializer in a variable definition\iref{dcl.init}, +\item as the initializer in a \grammarterm{new-expression}\iref{expr.new}, +\item in a \tcode{return} statement\iref{stmt.return}, +\item as a \grammarterm{for-range-initializer}\iref{stmt.iter}, +\item as a function argument\iref{expr.call}, +\item as a template argument\iref{temp.arg.nontype}, +\item as a subscript\iref{expr.sub}, +\item as an argument to a constructor invocation\iref{dcl.init,expr.type.conv}, +\item as an initializer for a non-static data member\iref{class.mem}, +\item in a \grammarterm{mem-initializer}\iref{class.base.init}, or +\item on the right-hand side of an assignment\iref{expr.assign}. \end{itemize} \begin{example} @@ -5812,7 +6317,7 @@ the program is ill-formed. \pnum -List-initialization of an object or reference of type \tcode{T} is defined as follows: +List-initialization of an object or reference of type \cvqual{cv} \tcode{T} is defined as follows: \begin{itemize} \item If the \grammarterm{braced-init-list} @@ -5835,7 +6340,7 @@ \end{example} \item If \tcode{T} is an aggregate class and the initializer list has a single element -of type \cvqual{cv} \tcode{U}, +of type \cvqual{cv1} \tcode{U}, where \tcode{U} is \tcode{T} or a class derived from \tcode{T}, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for @@ -5866,7 +6371,7 @@ \item Otherwise, if the initializer list has no elements and \tcode{T} is a class type with a default constructor, the object is value-initialized. -\item Otherwise, if \tcode{T} is a specialization of \tcode{std::initializer_list}, +\item Otherwise, if \tcode{T} is a specialization of \tcode{std::initializer_list}, the object is constructed as described below. \item Otherwise, if \tcode{T} is a class type, constructors are considered. @@ -5880,12 +6385,14 @@ struct S { S(std::initializer_list); // \#1 S(std::initializer_list); // \#2 - S(); // \#3 + S(std::initializer_list); // \#3 + S(); // \#4 // ... }; S s1 = { 1.0, 2.0, 3.0 }; // invoke \#1 S s2 = { 1, 2, 3 }; // invoke \#2 -S s3 = { }; // invoke \#3 +S s3{s2}; // invoke \#3 (not the copy constructor) +S s4 = { }; // invoke \#4 \end{codeblock} \end{example} @@ -5914,7 +6421,7 @@ \item Otherwise, if \tcode{T} is an enumeration with a fixed underlying type\iref{dcl.enum} \tcode{U}, -the \grammarterm{initializer-list} has a single element \tcode{v}, +the \grammarterm{initializer-list} has a single element \tcode{v} of scalar type, \tcode{v} can be implicitly converted to \tcode{U}, and the initialization is direct-list-initialization, the object is initialized with the value \tcode{T(v)}\iref{expr.type.conv}; @@ -6055,13 +6562,14 @@ corresponding element of the initializer list, and the \tcode{std::initializer_list} object is constructed to refer to that array. \begin{note} -A constructor or conversion function selected for the copy is required to be +A constructor or conversion function selected for the copy needs to be accessible\iref{class.access} in the context of the initializer list. \end{note} If a narrowing conversion is required to initialize any of the elements, the program is ill-formed. -Whether all backing arrays are distinct -(that is, are stored in non-overlapping objects) is unspecified. +\begin{note} +Backing arrays are potentially non-unique objects\iref{intro.object}. +\end{note} \pnum The backing array has the same lifetime as any other temporary @@ -6142,10 +6650,9 @@ \item from a floating-point type \tcode{T} to another floating-point type whose floating-point conversion rank is neither greater than nor equal to that of \tcode{T}, -except where the source is a constant expression and -the actual value after conversion -is within the range of values that can be represented (even if it cannot be represented exactly), -or +except where the result of the conversion is a constant expression and +either its value is finite and the conversion did not overflow, or +the values before and after the conversion are not finite, or \item from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit @@ -6202,7 +6709,7 @@ \rSec1[dcl.fct.def]{Function definitions}% \indextext{definition!function|(} -\rSec2[dcl.fct.def.general]{In general} +\rSec2[dcl.fct.def.general]{General} \pnum \indextext{body!function}% @@ -6211,8 +6718,10 @@ % \begin{bnf} \nontermdef{function-definition}\br - \opt{attribute-specifier-seq} \opt{decl-specifier-seq} declarator \opt{virt-specifier-seq} function-body\br - \opt{attribute-specifier-seq} \opt{decl-specifier-seq} declarator requires-clause function-body + \opt{attribute-specifier-seq} \opt{decl-specifier-seq} declarator \opt{virt-specifier-seq}\br + \bnfindent \opt{function-contract-specifier-seq} function-body\br + \opt{attribute-specifier-seq} \opt{decl-specifier-seq} declarator requires-clause\br + \bnfindent \opt{function-contract-specifier-seq} function-body \end{bnf} \begin{bnf} @@ -6220,15 +6729,28 @@ \opt{ctor-initializer} compound-statement\br function-try-block\br \terminal{=} \keyword{default} \terminal{;}\br - \terminal{=} \keyword{delete} \terminal{;} + deleted-function-body +\end{bnf} + +\begin{bnf} +\nontermdef{deleted-function-body}\br + \terminal{=} \keyword{delete} \terminal{;}\br + \terminal{=} \keyword{delete} \terminal{(} unevaluated-string \terminal{)} \terminal{;} \end{bnf} Any informal reference to the body of a function should be interpreted as a reference to -the non-terminal \grammarterm{function-body}. +the non-terminal \grammarterm{function-body}, +including, for a constructor, +default member initializers or default initialization +used to initialize +a base or member subobject in the absence of +a \grammarterm{mem-initializer-id}\iref{class.base.init}. The optional \grammarterm{attribute-specifier-seq} in a \grammarterm{function-definition} appertains to the function. -A \grammarterm{virt-specifier-seq} can be part of a \grammarterm{function-definition} -only if it is a \grammarterm{member-declaration}\iref{class.mem}. +A \grammarterm{function-definition} with a \grammarterm{virt-specifier-seq} +shall be a \grammarterm{member-declaration}\iref{class.mem}. +A \grammarterm{function-definition} with a \grammarterm{requires-clause} +shall define a templated function. \pnum In a \grammarterm{function-definition}, @@ -6337,9 +6859,9 @@ is called an \defnx{explicitly-defaulted}{definition!function!explicitly-defaulted} definition. A function that is explicitly defaulted shall \begin{itemize} -\item be a special member function or -a comparison operator function\iref{over.binary}, and -\item not have default arguments. +\item be a special member function\iref{special} or +a comparison operator function\iref{over.binary, class.compare.default}, and +\item not have default arguments\iref{dcl.fct.default}. \end{itemize} \pnum @@ -6385,6 +6907,9 @@ is implicitly inline\iref{dcl.inline}, and is implicitly constexpr\iref{dcl.constexpr} if it is constexpr-suitable. +\begin{note} +Other defaulted functions are not implicitly constexpr. +\end{note} \pnum \begin{example} @@ -6431,15 +6956,18 @@ (i.e., explicitly defaulted after its first declaration) is implicitly defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed. +\begin{note} +Declaring a function as defaulted after its first declaration +can provide efficient execution and concise definition +while enabling a stable binary interface to an evolving code base. +\end{note} A non-user-provided defaulted function (i.e., implicitly declared or explicitly defaulted in the class) that is not defined as deleted is implicitly defined when it is odr-used\iref{basic.def.odr} or needed for constant evaluation\iref{expr.const}. \begin{note} -Declaring a function as defaulted after its first declaration can provide -efficient execution and concise -definition while enabling a stable binary interface to an evolving code -base. +The implicit definition of a non-user-provided defaulted function +does not bind any names. \end{note} \pnum @@ -6465,11 +6993,8 @@ \indextext{definition!function!deleted}% \pnum -A \defnadj{deleted}{definition} of a function is -a function definition whose -\grammarterm{function-body} -is of the form -\tcode{= delete ;} +A \defnadj{deleted}{definition} of a function is a function definition +whose \grammarterm{function-body} is a \grammarterm{deleted-function-body} or an explicitly-defaulted definition of the function where the function is defined as deleted. A \defnadj{deleted}{function} is @@ -6479,6 +7004,12 @@ \pnum A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. + +\recommended +The resulting diagnostic message should include +the text of the \grammarterm{unevaluated-string}, +if one is supplied. + \begin{note} This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the @@ -6487,6 +7018,9 @@ function selected by overload resolution is referenced. The implicit odr-use\iref{term.odr.use} of a virtual function does not, by itself, constitute a reference. +The \grammarterm{unevaluated-string}, if present, +can be used to explain the rationale for deletion and/or +to suggest an alternative. \end{note} \pnum @@ -6607,17 +7141,23 @@ where $\tcode{p}_1$ denotes the object parameter and $\tcode{p}_{i+1}$ denotes the $i^\text{th}$ non-object function parameter -for a non-static member function, and +for an implicit object member function, and $\tcode{p}_i$ denotes the $i^\text{th}$ function parameter otherwise. -For a non-static member function, +For an implicit object member function, $\tcode{q}_1$ is an lvalue that denotes \tcode{*this}; any other $\tcode{q}_i$ is an lvalue that denotes the parameter copy corresponding to $\tcode{p}_i$, as described below. \pnum -A coroutine behaves as if its \grammarterm{function-body} were replaced by: +A coroutine behaves as if +the top-level cv-qualifiers in all +\grammarterm{parameter-declaration}s in the declarator +of its \grammarterm{function-definition} +were removed and +its \grammarterm{function-body} were replaced by +the following \defnadj{replacement}{body}: \begin{ncsimplebnf} \terminal{\{}\br \bnfindent \placeholder{promise-type} \exposid{promise} \placeholder{promise-constructor-arguments} \terminal{;}\br @@ -6682,6 +7222,13 @@ \end{itemize} \end{itemize} +\pnum +\begin{note} +An odr-use of a non-reference parameter +in a postcondition assertion +of a coroutine is ill-formed\iref{dcl.contract.func}. +\end{note} + \pnum If searches for the names \tcode{return_void} and \tcode{return_value} in the scope of the promise type each find any declarations, @@ -6715,7 +7262,8 @@ \pnum An implementation may need to allocate additional storage for a coroutine. This storage is known as the \defn{coroutine state} and is obtained by calling -a non-array allocation function\iref{basic.stc.dynamic.allocation}. +a non-array allocation function\iref{basic.stc.dynamic.allocation} +as part of the replacement body. The allocation function's name is looked up by searching for it in the scope of the promise type. \begin{itemize} \item @@ -6723,7 +7271,9 @@ overload resolution is performed on a function call created by assembling an argument list. The first argument is the amount of space requested, and is a prvalue of type \tcode{std::size_t}. -The lvalues $\tcode{p}_1 \dotsc \tcode{p}_n$ are the successive arguments. +The lvalues $\tcode{p}_1 \dotsc \tcode{p}_n$ +with their original types (including cv-qualifiers) +are the successive arguments. If no viable function is found\iref{over.match.viable}, overload resolution is performed again on a function call created by passing just @@ -6744,7 +7294,7 @@ the \tcode{::operator new(size_t, nothrow_t)} form is used. The allocation function used in this case shall have a non-throwing \grammarterm{noexcept-specifier}. -If the allocation function returns \keyword{nullptr}, the coroutine returns +If the allocation function returns \keyword{nullptr}, the coroutine transfers control to the caller of the coroutine and the return value is obtained by a call to \tcode{T::get_return_object_on_allocation_failure()}, where \tcode{T} is the promise type. @@ -6819,16 +7369,29 @@ \pnum When a coroutine is invoked, -after initializing its parameters\iref{expr.call}, -a copy is created for each coroutine parameter. -For a parameter of type \cv{}~\tcode{T}, -the copy is a variable of type \cv{}~\tcode{T} +a copy is created for each coroutine parameter +at the beginning of the replacement body. +For a parameter +whose original declaration specified the type \cv{}~\tcode{T}, +\begin{itemize} +\item +if \tcode{T} is a reference type, +the copy is a reference of type +\cv{}~\tcode{T} +bound to the same object as a parameter; +\item +otherwise, the copy is a variable +of type \cv{}~\tcode{T} with automatic storage duration that is direct-initialized from an xvalue of type \tcode{T} referring to the parameter. +\end{itemize} \begin{note} -An original parameter object is never -a const or volatile object\iref{basic.type.qualifier}. +An identifier in the \grammarterm{function-body} +that names one of these parameters +refers to the created copy, +not the original parameter\iref{expr.prim.id.unqual}. \end{note} + The initialization and destruction of each parameter copy occurs in the context of the called coroutine. Initializations of parameter copies are sequenced before the call to the @@ -6852,20 +7415,68 @@ The expression \keyword{co_await} \tcode{\exposid{promise}.final_suspend()} shall not be potentially-throwing\iref{except.spec}. +\rSec2[dcl.fct.def.replace]{Replaceable function definitions} + +\pnum +Certain functions +for which a definition is supplied by the implementation +are \defn{replaceable}. +A \Cpp{} program may +provide a definition with the signature of a replaceable function, +called a \defnadj{replacement}{function}. +The replacement function +is used instead of the default version +supplied by the implementation. +Such replacement occurs +prior to program startup\iref{basic.def.odr,basic.start}. +A declaration of the replacement function +\begin{itemize} +\item +shall not be inline, +\item +shall be attached to the global module, +\item +shall have \Cpp{} language linkage, +\item +shall have the same return type as the replaceable function, and +\item +if the function is declared in a standard library header, +shall be such that it would be valid as a redeclaration +of the declaration in that header; +\end{itemize} +no diagnostic is required. +\begin{note} +The one-definition rule\iref{basic.def.odr}) +applies to the definitions of a replaceable function +provided by the program. +The implementation-supplied function definition +is an otherwise-unnamed function with no linkage. +\end{note} + + \rSec1[dcl.struct.bind]{Structured binding declarations}% \indextext{structured binding declaration}% \indextext{declaration!structured binding|see{structured binding declaration}}% \pnum A structured binding declaration introduces the \grammarterm{identifier}{s} -$\tcode{v}_0$, $\tcode{v}_1$, $\tcode{v}_2, \dotsc$ +$\tcode{v}_0$, $\tcode{v}_1$, $\tcode{v}_2, \dotsc, \tcode{v}_{N-1}$ of the -\grammarterm{identifier-list} as names -of \defn{structured binding}{s}. +\grammarterm{sb-identifier-list} as names. +An \grammarterm{sb-identifier} that contains an ellipsis +introduces a structured binding pack\iref{temp.variadic}. +A \defn{structured binding} is either +an \grammarterm{sb-identifier} that does not contain an ellipsis or +an element of a structured binding pack. +The optional \grammarterm{attribute-specifier-seq} of +an \grammarterm{sb-identifier} +appertains to the associated structured bindings. Let \cv{} denote the \grammarterm{cv-qualifier}{s} in the \grammarterm{decl-specifier-seq} and -\placeholder{S} consist of the \grammarterm{storage-class-specifier}{s} of -the \grammarterm{decl-specifier-seq} (if any). +\placeholder{S} consist of +each \grammarterm{decl-specifier} of the \grammarterm{decl-specifier-seq} +that is \tcode{constexpr}, \tcode{constinit}, or +a \grammarterm{storage-class-specifier}. 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 @@ -6893,15 +7504,56 @@ \tcode{E} is never a reference type\iref{expr.prop}. \end{note} +\pnum +The \defn{structured binding size} of \tcode{E}, as defined below, +is the number of structured bindings +that need to be introduced by the structured binding declaration. +If there is no structured binding pack, +then the number of elements in the \grammarterm{sb-identifier-list} +shall be equal to the structured binding size of \tcode{E}. +Otherwise, the number of non-pack elements shall be no more than +the structured binding size of \tcode{E}; +the number of elements of the structured binding pack is +the structured binding size of \tcode{E} less +the number of non-pack elements in the\grammarterm{sb-identifier-list}. + +\pnum +Let $\textrm{SB}_i$ denote +the $i^\textrm{th}$ structured binding in the structured binding declaration +after expanding the structured binding pack, if any. +\begin{note} +If there is no structured binding pack, +then $\textrm{SB}_i$ denotes $\tcode{v}_i$. +\end{note} +\begin{example} +\begin{codeblock} +struct C { int x, y, z; }; + +template +void now_i_know_my() { + auto [a, b, c] = C(); // OK, $\textrm{SB}_0$ is \tcode{a}, $\textrm{SB}_1$ is \tcode{b}, and $\textrm{SB}_2$ is \tcode{c} + auto [d, ...e] = C(); // OK, $\textrm{SB}_0$ is \tcode{d}, the pack \tcode{e} $(\tcode{v}_1)$ contains two structured bindings: $\textrm{SB}_1$ and $\textrm{SB}_2$ + auto [...f, g] = C(); // OK, the pack \tcode{f} $(\tcode{v}_0)$ contains two structured bindings: $\textrm{SB}_0$ and $\textrm{SB}_1$, and $\textrm{SB}_2$ is \tcode{g} + auto [h, i, j, ...k] = C(); // OK, the pack \tcode{k} is empty + auto [l, m, n, o, ...p] = C(); // error: structured binding size is too small +} +\end{codeblock} +\end{example} + +\pnum +If a structured binding declaration appears as a \grammarterm{condition}, +the decision variable\iref{stmt.pre} of the condition is \exposid{e}. + \pnum If the \grammarterm{initializer} refers to one of the names introduced by the structured binding declaration, the program is ill-formed. \pnum -If \tcode{E} is an array type with element type \tcode{T}, the number -of elements in the \grammarterm{identifier-list} shall be equal to the -number of elements of \tcode{E}. Each $\tcode{v}_i$ is the name of an +If \tcode{E} is an array type with element type \tcode{T}, +the structured binding size of \tcode{E} is equal to the +number of elements of \tcode{E}. +Each $\textrm{SB}_i$ is the name of an lvalue that refers to the element $i$ of the array and whose type is \tcode{T}; the referenced type is \tcode{T}. \begin{note} @@ -6912,6 +7564,19 @@ auto f() -> int(&)[2]; auto [ x, y ] = f(); // \tcode{x} and \tcode{y} refer to elements in a copy of the array return value auto& [ xr, yr ] = f(); // \tcode{xr} and \tcode{yr} refer to elements in the array referred to by \tcode{f}'s return value + +auto g() -> int(&)[4]; + +template +void h(int (&arr)[N]) { + auto [a, ...b, c] = arr; // \tcode{a} names the first element of the array, \tcode{b} is a pack referring to the second and + // third elements, and \tcode{c} names the fourth element + auto& [...e] = arr; // \tcode{e} is a pack referring to the four elements of the array +} + +void call_h() { + h(g()); +} \end{codeblock} \end{example} @@ -6922,8 +7587,7 @@ the expression \tcode{std::tuple_size::value} shall be a well-formed integral constant expression and -the number of elements in -the \grammarterm{identifier-list} shall be equal to the value of that +the structured binding size of \tcode{E} is equal to the value of that expression. Let \tcode{i} be an index prvalue of type \tcode{std::size_t} corresponding to $\tcode{v}_i$. @@ -6931,7 +7595,7 @@ in the scope of \tcode{E}\iref{class.member.lookup} finds at least one declaration that is a function template whose first template parameter -is a non-type parameter, +is a constant template parameter, the initializer is \tcode{\exposidnc{e}.get()}. Otherwise, the initializer is \tcode{get(\exposid{e})}, where \tcode{get} undergoes argument-dependent lookup\iref{basic.lookup.argdep}. @@ -6953,9 +7617,15 @@ \placeholder{S} \terminal{U$_i$ r$_i$ =} initializer \terminal{;} \end{ncbnf} -Each $\tcode{v}_i$ is the name of an lvalue of type $\tcode{T}_i$ +Each $\textrm{SB}_i$ is the name of an lvalue of type $\tcode{T}_i$ that refers to the object bound to $\tcode{r}_i$; the referenced type is $\tcode{T}_i$. +The initialization of \exposid{e} and +any conversion of \exposid{e} considered as a decision variable\iref{stmt.pre} +is +sequenced before the initialization of any $\tcode{r}_i$. +The initialization of each $\tcode{r}_i$ is +sequenced before the initialization of any $\tcode{r}_j$ where $i < j$. \pnum Otherwise, @@ -6965,12 +7635,12 @@ well-formed when named as \tcode{\exposidnc{e}.\placeholder{name}} in the context of the structured binding, \tcode{E} shall not have an anonymous union member, and -the number of elements in the \grammarterm{identifier-list} shall be +the structured binding size of \tcode{E} is equal to the number of non-static data members of \tcode{E}. Designating the non-static data members of \tcode{E} as $\tcode{m}_0$, $\tcode{m}_1$, $\tcode{m}_2, \dotsc$ (in declaration order), -each $\tcode{v}_i$ is the +each $\textrm{SB}_i$ is the name of an lvalue that refers to the member \tcode{m}$_i$ of \exposid{e} and whose type is that of \tcode{\exposidnc{e}.$\tcode{m}_i$}\iref{expr.ref}; @@ -7328,11 +7998,26 @@ \pnum A \grammarterm{using-enum-declarator} names the set of declarations found by -lookup\iref{basic.lookup.unqual,basic.lookup.qual} -for the \grammarterm{using-enum-declarator}. +type-only lookup\iref{basic.lookup.general} +for the \grammarterm{using-enum-declarator}\iref{basic.lookup.unqual,basic.lookup.qual}. The \grammarterm{using-enum-declarator} shall designate a non-dependent type with a reachable \grammarterm{enum-specifier}. +\begin{example} +\begin{codeblock} +enum E { x }; +void f() { + int E; + using enum E; // OK +} +using F = E; +using enum F; // OK +template using EE = T; +void g() { + using enum EE; // OK +} +\end{codeblock} +\end{example} \pnum A \grammarterm{using-enum-declaration} @@ -8510,8 +9195,8 @@ \pnum \indextext{object!linkage specification}% \indextext{linkage!implementation-defined object}% -Linkage from \Cpp{} to objects defined in other languages and to objects -defined in \Cpp{} from other languages is \impldef{linkage of objects between \Cpp{} and other languages} and +Linkage from \Cpp{} to entities defined in other languages and to entities +defined in \Cpp{} from other languages is \impldef{linkage of entities between \Cpp{} and other languages} and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved.% @@ -8525,11 +9210,11 @@ \pnum \indextext{attribute!syntax and semantics}% Attributes specify additional information for various source constructs -such as types, variables, names, blocks, or translation units. +such as types, variables, names, contract assertions, blocks, or translation units. \begin{bnf} \nontermdef{attribute-specifier-seq}\br - \opt{attribute-specifier-seq} attribute-specifier + attribute-specifier \opt{attribute-specifier-seq} \end{bnf} \begin{bnf} @@ -8585,12 +9270,11 @@ \begin{bnf} \nontermdef{balanced-token-seq}\br - balanced-token\br - balanced-token-seq balanced-token + balanced-token \opt{balanced-token-seq} \end{bnf} \begin{bnf} -\microtypesetup{protrusion=false}\obeyspaces +\microtypesetup{protrusion=false} \nontermdef{balanced-token}\br \terminal{(} \opt{balanced-token-seq} \terminal{)}\br \terminal{[} \opt{balanced-token-seq} \terminal{]}\br @@ -8649,7 +9333,7 @@ \pnum Each \grammarterm{attribute-specifier-seq} is said to \defn{appertain} to some entity or statement, identified by the syntactic context -where it appears\iref{stmt.stmt,dcl.dcl,dcl.decl}. +where it appears\iref{stmt,dcl,dcl.decl}. If an \grammarterm{attribute-specifier-seq} that appertains to some entity or statement contains an \grammarterm{attribute} or \grammarterm{alignment-specifier} that is not allowed to apply to that @@ -8820,6 +9504,7 @@ \rSec2[dcl.attr.assume]{Assumption attribute} +\pnum The \grammarterm{attribute-token} \tcode{assume} may be applied to a null statement; such a statement is an \defn{assumption}. An \grammarterm{attribute-argument-clause} shall be present and @@ -8832,7 +9517,10 @@ If the converted expression would evaluate to \tcode{true} at the point where the assumption appears, the assumption has no effect. -Otherwise, the behavior is undefined. +Otherwise, +evaluation of the assumption has runtime-undefined behavior. + +\pnum \begin{note} The expression is potentially evaluated\iref{basic.def.odr}. The use of assumptions is intended to allow implementations @@ -8846,6 +9534,8 @@ if an implementation does not attempt to deduce any such information from assumptions. \end{note} + +\pnum \begin{example} \begin{codeblock} int divide_by_32(int x) { @@ -8860,86 +9550,6 @@ \end{codeblock} \end{example} -\rSec2[dcl.attr.depend]{Carries dependency attribute}% -\indextext{attribute!carries dependency} - -\pnum -The \grammarterm{attribute-token} \tcode{carries_dependency} specifies -dependency propagation into and out of functions. -No -\grammarterm{attribute-argument-clause} shall be present. The attribute may be -applied to a parameter of a function or lambda, in -which case it specifies that the initialization of the parameter carries a -dependency to\iref{intro.multithread} each lvalue-to-rvalue -conversion\iref{conv.lval} of that object. The attribute may also be applied -to a function or a lambda call operator, in which case it -specifies that the return value, if any, carries a dependency to the evaluation -of the function call expression. - -\pnum -The first declaration of a function shall specify the \tcode{carries_dependency} attribute for its -\grammarterm{declarator-id} if any declaration of the function specifies the -\tcode{carries_dependency} attribute. Furthermore, the first declaration of a function shall specify -the \tcode{carries_dependency} attribute for a parameter if any declaration of that function -specifies the \tcode{carries_dependency} attribute for that parameter. If a function or one of its -parameters is declared with the \tcode{carries_dependency} attribute in its first declaration in one -translation unit and the same function or one of its parameters is declared without the -\tcode{carries_dependency} attribute in its first declaration in another translation unit, the -program is ill-formed, no diagnostic required. - -\pnum -\begin{note} -The \tcode{carries_dependency} attribute does not change the meaning of the -program, but might result in generation of more efficient code. -\end{note} - -\pnum -\begin{example} -\begin{codeblock} -/* Translation unit A. */ - -struct foo { int* a; int* b; }; -std::atomic foo_head[10]; -int foo_array[10][10]; - -[[carries_dependency]] struct foo* f(int i) { - return foo_head[i].load(memory_order::consume); -} - -int g(int* x, int* y [[carries_dependency]]) { - return kill_dependency(foo_array[*x][*y]); -} - -/* Translation unit B. */ - -[[carries_dependency]] struct foo* f(int i); -int g(int* x, int* y [[carries_dependency]]); - -int c = 3; - -void h(int i) { - struct foo* p; - - p = f(i); - do_something_with(g(&c, p->a)); - do_something_with(g(p->a, &c)); -} -\end{codeblock} - -The \tcode{carries_dependency} attribute on function \tcode{f} means that the -return value carries a dependency out of \tcode{f}, so that the implementation -need not constrain ordering upon return from \tcode{f}. Implementations of -\tcode{f} and its caller may choose to preserve dependencies instead of emitting -hardware memory ordering instructions (a.k.a.\ fences). -Function \tcode{g}'s second parameter has a \tcode{carries_dependency} attribute, -but its first parameter does not. Therefore, function \tcode{h}'s first call to -\tcode{g} carries a dependency into \tcode{g}, but its second call does not. The -implementation might need to insert a fence prior to the second call to -\tcode{g}. -\end{example} -\indextext{attribute|)}% -\indextext{declaration|)} - \rSec2[dcl.attr.deprecated]{Deprecated attribute}% \indextext{attribute!deprecated} @@ -9062,6 +9672,52 @@ \end{codeblock} \end{example} +\rSec2[dcl.attr.indet]{Indeterminate storage} +\indextext{attribute!indeterminate} + +\pnum +The \grammarterm{attribute-token} \tcode{indeterminate} may be applied +to the definition of a block variable with automatic storage duration or +to a \grammarterm{parameter-declaration} of a function declaration. +No \grammarterm{attribute-argument-clause} shall be present. +The attribute specifies +that the storage of an object with automatic storage duration +is initially indeterminate rather than erroneous\iref{basic.indet}. + +\pnum +If a function parameter is declared with the \tcode{indeterminate} attribute, +it shall be so declared in the first declaration of its function. +If a function parameter is declared with +the \tcode{indeterminate} attribute in the first declaration of its function +in one translation unit and +the same function is declared without the \tcode{indeterminate} attribute +on the same parameter in its first declaration in another translation unit, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{note} +Reading from an uninitialized variable +that is marked \tcode{[[indeterminate]]} can cause undefined behavior. +\begin{codeblock} +void f(int); +void g() { + int x [[indeterminate]], y; + f(y); // erroneous behavior\iref{basic.indet} + f(x); // undefined behavior +} + +struct T { + T() {} + int x; +}; +int h(T t [[indeterminate]]) { + f(t.x); // undefined behavior when called below + return 0; +} +int _ = h(T()); +\end{codeblock} +\end{note} + \rSec2[dcl.attr.likelihood]{Likelihood attributes}% \indextext{attribute!likely} \indextext{attribute!unlikely} @@ -9131,15 +9787,20 @@ \pnum The \grammarterm{attribute-token} \tcode{maybe_unused} -indicates that a name or entity is possibly intentionally unused. +indicates that a name, label, or entity is possibly intentionally unused. No \grammarterm{attribute-argument-clause} shall be present. \pnum The attribute may be applied to the declaration of a class, -a \grammarterm{typedef-name}, -a variable (including a structured binding declaration), -a non-static data member, -a function, an enumeration, or an enumerator. +\grammarterm{typedef-name}, +variable (including a structured binding declaration), +structured binding, +result binding\iref{dcl.contract.res}, +non-static data member, +function, +enumeration, or +enumerator, or +to an \grammarterm{identifier} label\iref{stmt.label}. \pnum A name or entity declared without the \tcode{maybe_unused} attribute @@ -9157,6 +9818,8 @@ For a structured binding declaration not marked \tcode{maybe_unused}, implementations should not emit such a warning unless all of its structured bindings are unused. +For a label to which \tcode{maybe_unused} is applied, +implementations should not emit a warning that the label is used or unused. The value of a \grammarterm{has-attribute-expression} for the \tcode{maybe_unused} attribute should be \tcode{0} @@ -9169,9 +9832,13 @@ [[maybe_unused]] bool thing2) { [[maybe_unused]] bool b = thing1 && thing2; assert(b); +#ifdef NDEBUG + goto x; +#endif + [[maybe_unused]] x: } \end{codeblock} -Implementations should not warn that \tcode{b} is unused, +Implementations should not warn that \tcode{b} or \tcode{x} is unused, whether or not \tcode{NDEBUG} is defined. \end{example} @@ -9227,6 +9894,7 @@ \recommended Appearance of a nodiscard call as a potentially-evaluated discarded-value expression\iref{expr.prop} +of non-void type is discouraged unless explicitly cast to \keyword{void}. Implementations should issue a warning in such cases. The value of @@ -9283,10 +9951,11 @@ translation unit, the program is ill-formed, no diagnostic required. \pnum -If a function \tcode{f} is called where \tcode{f} was previously declared with the \tcode{noreturn} -attribute and \tcode{f} eventually returns, the behavior is undefined. +If a function \tcode{f} is invoked where \tcode{f} was previously declared with the \tcode{noreturn} +attribute and that invocation eventually returns, +the behavior is runtime-undefined. \begin{note} -The function may +The function can terminate by throwing an exception. \end{note} @@ -9357,3 +10026,6 @@ could have the same address as \tcode{buckets} if their respective types are all empty. \end{example} + +\indextext{attribute|)}% +\indextext{declaration|)} diff --git a/source/diagnostics.tex b/source/diagnostics.tex index 12a3cb75b0..1f5f1ad48a 100644 --- a/source/diagnostics.tex +++ b/source/diagnostics.tex @@ -20,7 +20,8 @@ \ref{assertions} & Assertions & \tcode{} \\ \rowsep \ref{errno} & Error numbers & \tcode{} \\ \rowsep \ref{syserr} & System error support & \tcode{} \\ \rowsep -\ref{stacktrace} & Stacktrace & \tcode{} \\ +\ref{stacktrace} & Stacktrace & \tcode{} \\ \rowsep +\ref{debugging} & Debugging & \tcode{} \\ \end{libsumtab} \rSec1[std.exceptions]{Exception classes} @@ -81,8 +82,8 @@ namespace std { class logic_error : public exception { public: - explicit logic_error(const string& what_arg); - explicit logic_error(const char* what_arg); + constexpr explicit logic_error(const string& what_arg); + constexpr explicit logic_error(const char* what_arg); }; } \end{codeblock} @@ -97,7 +98,7 @@ \indexlibraryctor{logic_error}% \begin{itemdecl} -logic_error(const string& what_arg); +constexpr logic_error(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -108,7 +109,7 @@ \indexlibraryctor{logic_error}% \begin{itemdecl} -logic_error(const char* what_arg); +constexpr logic_error(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -124,8 +125,8 @@ namespace std { class domain_error : public logic_error { public: - explicit domain_error(const string& what_arg); - explicit domain_error(const char* what_arg); + constexpr explicit domain_error(const string& what_arg); + constexpr explicit domain_error(const char* what_arg); }; } \end{codeblock} @@ -138,7 +139,7 @@ \indexlibraryctor{domain_error}% \begin{itemdecl} -domain_error(const string& what_arg); +constexpr domain_error(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -149,7 +150,7 @@ \indexlibraryctor{domain_error}% \begin{itemdecl} -domain_error(const char* what_arg); +constexpr domain_error(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -165,8 +166,8 @@ namespace std { class invalid_argument : public logic_error { public: - explicit invalid_argument(const string& what_arg); - explicit invalid_argument(const char* what_arg); + constexpr explicit invalid_argument(const string& what_arg); + constexpr explicit invalid_argument(const char* what_arg); }; } \end{codeblock} @@ -178,7 +179,7 @@ \indexlibraryctor{invalid_argument}% \begin{itemdecl} -invalid_argument(const string& what_arg); +constexpr invalid_argument(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -189,7 +190,7 @@ \indexlibraryctor{invalid_argument}% \begin{itemdecl} -invalid_argument(const char* what_arg); +constexpr invalid_argument(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -205,8 +206,8 @@ namespace std { class length_error : public logic_error { public: - explicit length_error(const string& what_arg); - explicit length_error(const char* what_arg); + constexpr explicit length_error(const string& what_arg); + constexpr explicit length_error(const char* what_arg); }; } \end{codeblock} @@ -220,7 +221,7 @@ \indexlibraryctor{length_error}% \begin{itemdecl} -length_error(const string& what_arg); +constexpr length_error(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -231,7 +232,7 @@ \indexlibraryctor{length_error}% \begin{itemdecl} -length_error(const char* what_arg); +constexpr length_error(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -247,8 +248,8 @@ namespace std { class out_of_range : public logic_error { public: - explicit out_of_range(const string& what_arg); - explicit out_of_range(const char* what_arg); + constexpr explicit out_of_range(const string& what_arg); + constexpr explicit out_of_range(const char* what_arg); }; } \end{codeblock} @@ -262,7 +263,7 @@ \indexlibraryctor{out_of_range}% \begin{itemdecl} -out_of_range(const string& what_arg); +constexpr out_of_range(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -273,7 +274,7 @@ \indexlibraryctor{out_of_range}% \begin{itemdecl} -out_of_range(const char* what_arg); +constexpr out_of_range(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -289,8 +290,8 @@ namespace std { class runtime_error : public exception { public: - explicit runtime_error(const string& what_arg); - explicit runtime_error(const char* what_arg); + constexpr explicit runtime_error(const string& what_arg); + constexpr explicit runtime_error(const char* what_arg); }; } \end{codeblock} @@ -303,7 +304,7 @@ \indexlibraryctor{runtime_error}% \begin{itemdecl} -runtime_error(const string& what_arg); +constexpr runtime_error(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -314,7 +315,7 @@ \indexlibraryctor{runtime_error}% \begin{itemdecl} -runtime_error(const char* what_arg); +constexpr runtime_error(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -330,8 +331,8 @@ namespace std { class range_error : public runtime_error { public: - explicit range_error(const string& what_arg); - explicit range_error(const char* what_arg); + constexpr explicit range_error(const string& what_arg); + constexpr explicit range_error(const char* what_arg); }; } \end{codeblock} @@ -344,7 +345,7 @@ \indexlibraryctor{range_error}% \begin{itemdecl} -range_error(const string& what_arg); +constexpr range_error(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -355,7 +356,7 @@ \indexlibraryctor{range_error}% \begin{itemdecl} -range_error(const char* what_arg); +constexpr range_error(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -371,8 +372,8 @@ namespace std { class overflow_error : public runtime_error { public: - explicit overflow_error(const string& what_arg); - explicit overflow_error(const char* what_arg); + constexpr explicit overflow_error(const string& what_arg); + constexpr explicit overflow_error(const char* what_arg); }; } \end{codeblock} @@ -384,7 +385,7 @@ \indexlibraryctor{overflow_error}% \begin{itemdecl} -overflow_error(const string& what_arg); +constexpr overflow_error(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -395,7 +396,7 @@ \indexlibraryctor{overflow_error}% \begin{itemdecl} -overflow_error(const char* what_arg); +constexpr overflow_error(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -411,8 +412,8 @@ namespace std { class underflow_error : public runtime_error { public: - explicit underflow_error(const string& what_arg); - explicit underflow_error(const char* what_arg); + constexpr explicit underflow_error(const string& what_arg); + constexpr explicit underflow_error(const char* what_arg); }; } \end{codeblock} @@ -424,7 +425,7 @@ \indexlibraryctor{underflow_error}% \begin{itemdecl} -underflow_error(const string& what_arg); +constexpr underflow_error(const string& what_arg); \end{itemdecl} \begin{itemdescr} @@ -435,7 +436,7 @@ \indexlibraryctor{underflow_error}% \begin{itemdecl} -underflow_error(const char* what_arg); +constexpr underflow_error(const char* what_arg); \end{itemdecl} \begin{itemdescr} @@ -451,25 +452,56 @@ \pnum The header \libheaderdef{cassert} provides a macro for documenting \Cpp{} program assertions and a mechanism -for disabling the assertion checks. +for disabling the assertion checks through defining the macro \tcode{NDEBUG}. \rSec2[cassert.syn]{Header \tcode{} synopsis} -\indexlibraryglobal{assert}% \begin{codeblock} -#define assert(E) @\seebelow@ +#define @\libmacro{assert}@(...) @\seebelow@ \end{codeblock} +\rSec2[assertions.assert]{The \tcode{assert} macro} + \pnum -\indextext{static_assert@\tcode{static_assert}!not macro}% -The contents are the same as the C standard library header -\libheader{assert.h}, -except that a macro named \keyword{static_assert} -is not defined. +If \tcode{NDEBUG} is defined as a macro name +at the point in the source file where \tcode{} is included, +the \tcode{assert} macro is defined as +\begin{codeblock} +#define @\libmacro{assert}@(...) ((void)0) +\end{codeblock} -\xrefc{7.2} +\pnum +Otherwise, the \libmacro{assert} macro puts a diagnostic test into programs; +it expands to an expression of type \keyword{void} which +has the following effects: -\rSec2[assertions.assert]{The \tcode{assert} macro} +\begin{itemize} +\item +\mname{VA_ARGS} is evaluated and contextually converted to \tcode{bool}. +\item +If the evaluation yields \tcode{true} there are no further effects. +\item +Otherwise, the \tcode{assert} macro's expression +creates a diagnostic on the standard error stream in an +\impldef{format of diagnostic created by \tcode{assert} macro's expression} +format and calls \tcode{abort()}. +The diagnostic contains \tcode{\#}\mname{VA_ARGS} and +information on +the name of the source file, +the source line number, and +the name of the enclosing function +(such as provided by \tcode{source_location::current()}). +\end{itemize} + +\pnum +If \mname{VA_ARGS} does not expand to +an \grammarterm{assignment-expression}, +the program is ill-formed. + +\pnum +The macro \tcode{assert} is redefined according to +the current state of \tcode{NDEBUG} each time that +\tcode{} is included. \pnum An expression \tcode{assert(E)} @@ -489,7 +521,7 @@ \pnum The contents of the header \libheaderdef{cerrno} are the same as the POSIX header -\libheader{errno.h}, except that \tcode{errno} shall be defined as a macro. +\libheader{errno.h}, except that \libmacro{errno} shall be defined as a macro. \begin{note} The intent is to remain in close alignment with the POSIX standard. \end{note} @@ -497,158 +529,83 @@ \rSec2[cerrno.syn]{Header \tcode{} synopsis} -\indexlibraryglobal{errno}% -\indexlibraryglobal{E2BIG}% -\indexlibraryglobal{EACCES}% -\indexlibraryglobal{EADDRINUSE}% -\indexlibraryglobal{EADDRNOTAVAIL}% -\indexlibraryglobal{EAFNOSUPPORT}% -\indexlibraryglobal{EAGAIN}% -\indexlibraryglobal{EALREADY}% -\indexlibraryglobal{EBADF}% -\indexlibraryglobal{EBADMSG}% -\indexlibraryglobal{EBUSY}% -\indexlibraryglobal{ECANCELED}% -\indexlibraryglobal{ECHILD}% -\indexlibraryglobal{ECONNABORTED}% -\indexlibraryglobal{ECONNREFUSED}% -\indexlibraryglobal{ECONNRESET}% -\indexlibraryglobal{EDEADLK}% -\indexlibraryglobal{EDESTADDRREQ}% -\indexlibraryglobal{EDOM}% -\indexlibraryglobal{EEXIST}% -\indexlibraryglobal{EFAULT}% -\indexlibraryglobal{EFBIG}% -\indexlibraryglobal{EHOSTUNREACH}% -\indexlibraryglobal{EIDRM}% -\indexlibraryglobal{EILSEQ}% -\indexlibraryglobal{EINPROGRESS}% -\indexlibraryglobal{EINTR}% -\indexlibraryglobal{EINVAL}% -\indexlibraryglobal{EIO}% -\indexlibraryglobal{EISCONN}% -\indexlibraryglobal{EISDIR}% -\indexlibraryglobal{ELOOP}% -\indexlibraryglobal{EMFILE}% -\indexlibraryglobal{EMLINK}% -\indexlibraryglobal{EMSGSIZE}% -\indexlibraryglobal{ENAMETOOLONG}% -\indexlibraryglobal{ENETDOWN}% -\indexlibraryglobal{ENETRESET}% -\indexlibraryglobal{ENETUNREACH}% -\indexlibraryglobal{ENFILE}% -\indexlibraryglobal{ENOBUFS}% -\indexlibraryglobal{ENODEV}% -\indexlibraryglobal{ENOENT}% -\indexlibraryglobal{ENOEXEC}% -\indexlibraryglobal{ENOLCK}% -\indexlibraryglobal{ENOLINK}% -\indexlibraryglobal{ENOMEM}% -\indexlibraryglobal{ENOMSG}% -\indexlibraryglobal{ENOPROTOOPT}% -\indexlibraryglobal{ENOSPC}% -\indexlibraryglobal{ENOSYS}% -\indexlibraryglobal{ENOTCONN}% -\indexlibraryglobal{ENOTDIR}% -\indexlibraryglobal{ENOTEMPTY}% -\indexlibraryglobal{ENOTRECOVERABLE}% -\indexlibraryglobal{ENOTSOCK}% -\indexlibraryglobal{ENOTSUP}% -\indexlibraryglobal{ENOTTY}% -\indexlibraryglobal{ENXIO}% -\indexlibraryglobal{EOPNOTSUPP}% -\indexlibraryglobal{EOVERFLOW}% -\indexlibraryglobal{EOWNERDEAD}% -\indexlibraryglobal{EPERM}% -\indexlibraryglobal{EPIPE}% -\indexlibraryglobal{EPROTO}% -\indexlibraryglobal{EPROTONOSUPPORT}% -\indexlibraryglobal{EPROTOTYPE}% -\indexlibraryglobal{ERANGE}% -\indexlibraryglobal{EROFS}% -\indexlibraryglobal{ESPIPE}% -\indexlibraryglobal{ESRCH}% -\indexlibraryglobal{ETIMEDOUT}% -\indexlibraryglobal{ETXTBSY}% -\indexlibraryglobal{EWOULDBLOCK}% -\indexlibraryglobal{EXDEV}% \begin{codeblock} -#define errno @\seebelow@ - -#define E2BIG @\seebelow@ // freestanding -#define EACCES @\seebelow@ // freestanding -#define EADDRINUSE @\seebelow@ // freestanding -#define EADDRNOTAVAIL @\seebelow@ // freestanding -#define EAFNOSUPPORT @\seebelow@ // freestanding -#define EAGAIN @\seebelow@ // freestanding -#define EALREADY @\seebelow@ // freestanding -#define EBADF @\seebelow@ // freestanding -#define EBADMSG @\seebelow@ // freestanding -#define EBUSY @\seebelow@ // freestanding -#define ECANCELED @\seebelow@ // freestanding -#define ECHILD @\seebelow@ // freestanding -#define ECONNABORTED @\seebelow@ // freestanding -#define ECONNREFUSED @\seebelow@ // freestanding -#define ECONNRESET @\seebelow@ // freestanding -#define EDEADLK @\seebelow@ // freestanding -#define EDESTADDRREQ @\seebelow@ // freestanding -#define EDOM @\seebelow@ // freestanding -#define EEXIST @\seebelow@ // freestanding -#define EFAULT @\seebelow@ // freestanding -#define EFBIG @\seebelow@ // freestanding -#define EHOSTUNREACH @\seebelow@ // freestanding -#define EIDRM @\seebelow@ // freestanding -#define EILSEQ @\seebelow@ // freestanding -#define EINPROGRESS @\seebelow@ // freestanding -#define EINTR @\seebelow@ // freestanding -#define EINVAL @\seebelow@ // freestanding -#define EIO @\seebelow@ // freestanding -#define EISCONN @\seebelow@ // freestanding -#define EISDIR @\seebelow@ // freestanding -#define ELOOP @\seebelow@ // freestanding -#define EMFILE @\seebelow@ // freestanding -#define EMLINK @\seebelow@ // freestanding -#define EMSGSIZE @\seebelow@ // freestanding -#define ENAMETOOLONG @\seebelow@ // freestanding -#define ENETDOWN @\seebelow@ // freestanding -#define ENETRESET @\seebelow@ // freestanding -#define ENETUNREACH @\seebelow@ // freestanding -#define ENFILE @\seebelow@ // freestanding -#define ENOBUFS @\seebelow@ // freestanding -#define ENODEV @\seebelow@ // freestanding -#define ENOENT @\seebelow@ // freestanding -#define ENOEXEC @\seebelow@ // freestanding -#define ENOLCK @\seebelow@ // freestanding -#define ENOLINK @\seebelow@ // freestanding -#define ENOMEM @\seebelow@ // freestanding -#define ENOMSG @\seebelow@ // freestanding -#define ENOPROTOOPT @\seebelow@ // freestanding -#define ENOSPC @\seebelow@ // freestanding -#define ENOSYS @\seebelow@ // freestanding -#define ENOTCONN @\seebelow@ // freestanding -#define ENOTDIR @\seebelow@ // freestanding -#define ENOTEMPTY @\seebelow@ // freestanding -#define ENOTRECOVERABLE @\seebelow@ // freestanding -#define ENOTSOCK @\seebelow@ // freestanding -#define ENOTSUP @\seebelow@ // freestanding -#define ENOTTY @\seebelow@ // freestanding -#define ENXIO @\seebelow@ // freestanding -#define EOPNOTSUPP @\seebelow@ // freestanding -#define EOVERFLOW @\seebelow@ // freestanding -#define EOWNERDEAD @\seebelow@ // freestanding -#define EPERM @\seebelow@ // freestanding -#define EPIPE @\seebelow@ // freestanding -#define EPROTO @\seebelow@ // freestanding -#define EPROTONOSUPPORT @\seebelow@ // freestanding -#define EPROTOTYPE @\seebelow@ // freestanding -#define ERANGE @\seebelow@ // freestanding -#define EROFS @\seebelow@ // freestanding -#define ESPIPE @\seebelow@ // freestanding -#define ESRCH @\seebelow@ // freestanding -#define ETIMEDOUT @\seebelow@ // freestanding -#define ETXTBSY @\seebelow@ // freestanding -#define EWOULDBLOCK @\seebelow@ // freestanding -#define EXDEV @\seebelow@ // freestanding +#define @\libmacro{errno}@ @\seebelow@ + +#define @\libmacro{E2BIG}@ @\seebelow@ // freestanding +#define @\libmacro{EACCES}@ @\seebelow@ // freestanding +#define @\libmacro{EADDRINUSE}@ @\seebelow@ // freestanding +#define @\libmacro{EADDRNOTAVAIL}@ @\seebelow@ // freestanding +#define @\libmacro{EAFNOSUPPORT}@ @\seebelow@ // freestanding +#define @\libmacro{EAGAIN}@ @\seebelow@ // freestanding +#define @\libmacro{EALREADY}@ @\seebelow@ // freestanding +#define @\libmacro{EBADF}@ @\seebelow@ // freestanding +#define @\libmacro{EBADMSG}@ @\seebelow@ // freestanding +#define @\libmacro{EBUSY}@ @\seebelow@ // freestanding +#define @\libmacro{ECANCELED}@ @\seebelow@ // freestanding +#define @\libmacro{ECHILD}@ @\seebelow@ // freestanding +#define @\libmacro{ECONNABORTED}@ @\seebelow@ // freestanding +#define @\libmacro{ECONNREFUSED}@ @\seebelow@ // freestanding +#define @\libmacro{ECONNRESET}@ @\seebelow@ // freestanding +#define @\libmacro{EDEADLK}@ @\seebelow@ // freestanding +#define @\libmacro{EDESTADDRREQ}@ @\seebelow@ // freestanding +#define @\libmacro{EDOM}@ @\seebelow@ // freestanding +#define @\libmacro{EEXIST}@ @\seebelow@ // freestanding +#define @\libmacro{EFAULT}@ @\seebelow@ // freestanding +#define @\libmacro{EFBIG}@ @\seebelow@ // freestanding +#define @\libmacro{EHOSTUNREACH}@ @\seebelow@ // freestanding +#define @\libmacro{EIDRM}@ @\seebelow@ // freestanding +#define @\libmacro{EILSEQ}@ @\seebelow@ // freestanding +#define @\libmacro{EINPROGRESS}@ @\seebelow@ // freestanding +#define @\libmacro{EINTR}@ @\seebelow@ // freestanding +#define @\libmacro{EINVAL}@ @\seebelow@ // freestanding +#define @\libmacro{EIO}@ @\seebelow@ // freestanding +#define @\libmacro{EISCONN}@ @\seebelow@ // freestanding +#define @\libmacro{EISDIR}@ @\seebelow@ // freestanding +#define @\libmacro{ELOOP}@ @\seebelow@ // freestanding +#define @\libmacro{EMFILE}@ @\seebelow@ // freestanding +#define @\libmacro{EMLINK}@ @\seebelow@ // freestanding +#define @\libmacro{EMSGSIZE}@ @\seebelow@ // freestanding +#define @\libmacro{ENAMETOOLONG}@ @\seebelow@ // freestanding +#define @\libmacro{ENETDOWN}@ @\seebelow@ // freestanding +#define @\libmacro{ENETRESET}@ @\seebelow@ // freestanding +#define @\libmacro{ENETUNREACH}@ @\seebelow@ // freestanding +#define @\libmacro{ENFILE}@ @\seebelow@ // freestanding +#define @\libmacro{ENOBUFS}@ @\seebelow@ // freestanding +#define @\libmacro{ENODEV}@ @\seebelow@ // freestanding +#define @\libmacro{ENOENT}@ @\seebelow@ // freestanding +#define @\libmacro{ENOEXEC}@ @\seebelow@ // freestanding +#define @\libmacro{ENOLCK}@ @\seebelow@ // freestanding +#define @\libmacro{ENOLINK}@ @\seebelow@ // freestanding +#define @\libmacro{ENOMEM}@ @\seebelow@ // freestanding +#define @\libmacro{ENOMSG}@ @\seebelow@ // freestanding +#define @\libmacro{ENOPROTOOPT}@ @\seebelow@ // freestanding +#define @\libmacro{ENOSPC}@ @\seebelow@ // freestanding +#define @\libmacro{ENOSYS}@ @\seebelow@ // freestanding +#define @\libmacro{ENOTCONN}@ @\seebelow@ // freestanding +#define @\libmacro{ENOTDIR}@ @\seebelow@ // freestanding +#define @\libmacro{ENOTEMPTY}@ @\seebelow@ // freestanding +#define @\libmacro{ENOTRECOVERABLE}@ @\seebelow@ // freestanding +#define @\libmacro{ENOTSOCK}@ @\seebelow@ // freestanding +#define @\libmacro{ENOTSUP}@ @\seebelow@ // freestanding +#define @\libmacro{ENOTTY}@ @\seebelow@ // freestanding +#define @\libmacro{ENXIO}@ @\seebelow@ // freestanding +#define @\libmacro{EOPNOTSUPP}@ @\seebelow@ // freestanding +#define @\libmacro{EOVERFLOW}@ @\seebelow@ // freestanding +#define @\libmacro{EOWNERDEAD}@ @\seebelow@ // freestanding +#define @\libmacro{EPERM}@ @\seebelow@ // freestanding +#define @\libmacro{EPIPE}@ @\seebelow@ // freestanding +#define @\libmacro{EPROTO}@ @\seebelow@ // freestanding +#define @\libmacro{EPROTONOSUPPORT}@ @\seebelow@ // freestanding +#define @\libmacro{EPROTOTYPE}@ @\seebelow@ // freestanding +#define @\libmacro{ERANGE}@ @\seebelow@ // freestanding +#define @\libmacro{EROFS}@ @\seebelow@ // freestanding +#define @\libmacro{ESPIPE}@ @\seebelow@ // freestanding +#define @\libmacro{ESRCH}@ @\seebelow@ // freestanding +#define @\libmacro{ETIMEDOUT}@ @\seebelow@ // freestanding +#define @\libmacro{ETXTBSY}@ @\seebelow@ // freestanding +#define @\libmacro{EWOULDBLOCK}@ @\seebelow@ // freestanding +#define @\libmacro{EXDEV}@ @\seebelow@ // freestanding \end{codeblock} \pnum @@ -680,9 +637,6 @@ \indexlibraryglobal{error_code}% \indexlibraryglobal{error_condition}% \indexlibraryglobal{system_error}% -\indexlibraryglobal{is_error_code_enum}% -\indexlibraryglobal{is_error_condition_enum}% -\indexlibraryglobal{errc}% \begin{codeblock} #include // see \ref{compare.syn} @@ -696,12 +650,12 @@ class system_error; template - struct is_error_code_enum : public false_type {}; + struct @\libglobal{is_error_code_enum}@ : public false_type {}; template - struct is_error_condition_enum : public false_type {}; + struct @\libglobal{is_error_condition_enum}@ : public false_type {}; - enum class errc { // freestanding + enum class @\libglobal{errc}@ { // freestanding address_family_not_supported, // \tcode{EAFNOSUPPORT} address_in_use, // \tcode{EADDRINUSE} address_not_available, // \tcode{EADDRNOTAVAIL} @@ -804,7 +758,7 @@ // \ref{syserr}, system error support template - constexpr bool is_error_code_enum_v = is_error_code_enum::value; + constexpr bool @\libglobal{is_error_code_enum_v}@ = is_error_code_enum::value; template constexpr bool is_error_condition_enum_v = is_error_condition_enum::value; } @@ -1977,7 +1931,7 @@ const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; - [[nodiscard]] bool empty() const noexcept; + bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; @@ -2221,7 +2175,7 @@ \indexlibrarymember{empty}{basic_stacktrace}% \begin{itemdecl} -[[nodiscard]] bool empty() const noexcept; +bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -2400,7 +2354,7 @@ Equivalent to: \tcode{return os << to_string(st);} \end{itemdescr} -\rSec3[stacktrace.format]{Formatting support} +\rSec2[stacktrace.format]{Formatting support} \begin{itemdecl} template<> struct formatter; @@ -2442,7 +2396,7 @@ copying \tcode{to_string(s)} through the output iterator of the context. \end{itemdescr} -\rSec3[stacktrace.basic.hash]{Hash support} +\rSec2[stacktrace.basic.hash]{Hash support} \begin{itemdecl} template<> struct hash; @@ -2453,3 +2407,99 @@ \pnum The specializations are enabled\iref{unord.hash}. \end{itemdescr} + +\rSec1[debugging]{Debugging} + +\rSec2[debugging.general]{General} + +\pnum +Subclause \ref{debugging} describes functionality to introspect and +interact with the execution of the program. + +\begin{note} +The facilities provided by the debugging functionality interact with a program +that could be tracing the execution of a \Cpp{} program, such as a debugger. +\end{note} + +\rSec2[debugging.syn]{Header \tcode{} synopsis} + +\indexheader{debugging}% +\begin{codeblock} +// all freestanding +namespace std { + // \ref{debugging.utility}, utility + void breakpoint() noexcept; + void breakpoint_if_debugging() noexcept; + bool is_debugger_present() noexcept; +} +\end{codeblock} + +\rSec2[debugging.utility]{Utility} + +\indexlibraryglobal{breakpoint}% +\begin{itemdecl} +void breakpoint() noexcept; +\end{itemdecl} + +\begin{itemdescr} + +\pnum +The semantics of this function are \impldef{semantics of \tcode{breakpoint}}. + +\begin{note} +It is intended that, when invoked with a debugger present, the execution of the +program temporarily halts and execution is handed to the debugger until the +program is either terminated by the debugger or the debugger resumes execution +of the program as if the function was not invoked. In particular, there is no +intent for a call to this function to accomodate resumption of the program in a +different manner. If there is no debugger present, execution of the program can +end abnormally. +\end{note} + +\end{itemdescr} + +\indexlibraryglobal{breakpoint_if_debugging}% +\begin{itemdecl} +void breakpoint_if_debugging() noexcept; +\end{itemdecl} + +\begin{itemdescr} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (is_debugger_present()) breakpoint(); +\end{codeblock} + +\end{itemdescr} + +\indexlibraryglobal{is_debugger_present}% +\begin{itemdecl} +bool is_debugger_present() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\required +This function has no preconditions. + +\pnum +\default +\impldef{default semantics of \tcode{is_debugger_present}}. + +\begin{note} +It is intended that, using an immediate (uncached) query to determine if the +program is being traced by a debugger, an implementation returns \tcode{true} +only when tracing the execution of the program with a debugger. On Windows or +equivalent systems, this can be achieved by calling the +\tcode{::IsDebuggerPresent()} Win32 function. For systems compatible with +ISO/IEC 23360:2021, this can be achieved by checking for a tracing process, with +a best-effort determination that such a tracing process is a debugger. +\end{note} + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. + +\end{itemdescr} diff --git a/source/exceptions.tex b/source/exceptions.tex index c4cc789ff9..79684e4c51 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -257,14 +257,14 @@ \pnum Throwing an exception -initializes a temporary object, +initializes an object with dynamic storage duration, called the \defnx{exception object}{exception handling!exception object}. If the type of the exception object would be an incomplete type\iref{basic.types.general}, an abstract class type\iref{class.abstract}, or a pointer to an incomplete type other than -\cv{}~\keyword{void}\iref{basic.compound} +\cv{}~\keyword{void}\iref{basic.compound}, the program is ill-formed. \pnum @@ -309,12 +309,33 @@ \pnum \indextext{exception handling!exception object!constructor}% \indextext{exception handling!exception object!destructor}% -When the thrown object is a class object, the constructor selected for -the copy-initialization as well as the constructor selected for -a copy-initialization considering the thrown object as an lvalue -shall be non-deleted and accessible, even if the copy/move operation is -elided\iref{class.copy.elision}. -The destructor is potentially invoked\iref{class.dtor}. +Let \tcode{T} denote the type of the exception object. +Copy-initialization of an object of type \tcode{T} from +an lvalue of type \tcode{const T} in a context unrelated to \tcode{T} +shall be well-formed. +If \tcode{T} is a class type, +the selected constructor is odr-used\iref{basic.def.odr} and +the destructor of \tcode{T} is potentially invoked\iref{class.dtor}. + +\pnum +\indextext{exception handling!uncaught}% +An exception is considered \defnx{uncaught}{uncaught exception} +after completing the initialization of the exception object +until completing the activation of a handler for the exception\iref{except.handle}. +\begin{note} +As a consequence, an exception is considered uncaught +during any stack unwinding resulting from it being thrown. +\end{note} + +\pnum +\indexlibraryglobal{uncaught_exceptions}% +If an exception is rethrown\iref{expr.throw,propagation}, +it is considered uncaught from the point of rethrow +until the rethrown exception is caught. +\begin{note} +The function \tcode{std::uncaught_exceptions}\iref{uncaught.exceptions} +returns the number of uncaught exceptions in the current thread. +\end{note} \pnum \indextext{exception handling!rethrow}% @@ -330,7 +351,7 @@ \indextext{exception handling!terminate called@\tcode{terminate} called}% \indextext{\idxcode{terminate}!called}% If the exception handling mechanism -handling an uncaught exception\iref{except.uncaught} +handling an uncaught exception directly invokes a function that exits via an exception, the function \tcode{std::terminate} is invoked\iref{except.terminate}. \begin{example} @@ -358,7 +379,7 @@ \end{note} -\rSec1[except.ctor]{Constructors and destructors}% +\rSec1[except.ctor]{Stack unwinding}% \indextext{exception handling!constructors and destructors}% \indextext{constructor!exception handling|see{exception handling, constructors and destructors}}% \indextext{destructor!exception handling|see{exception handling, constructors and destructors}} @@ -421,7 +442,8 @@ \end{note} \indextext{subobject!initialized, known to be}% A subobject is \defn{known to be initialized} -if its initialization is specified +if it is not an anonymous union member and +its initialization is specified \begin{itemize} \item in \ref{class.base.init} for initialization by constructor, \item in \ref{class.copy.ctor} for initialization by defaulted copy/move constructor, @@ -602,10 +624,7 @@ \tcode{...} in a handler's \grammarterm{exception-declaration} -functions similarly to -\tcode{...} -in a function parameter declaration; -it specifies a match for any exception. +specifies a match for any exception. If present, a \tcode{...} handler shall be the last handler for its try block. @@ -616,6 +635,40 @@ handler continues in a dynamically surrounding try block of the same thread. +\pnum +\indextext{exception handling!terminate called@\tcode{terminate} called}% +\indextext{\idxcode{terminate}!called}% +If the search for a handler +exits the function body of a function with a +non-throwing exception specification, +the function \tcode{std::terminate}\iref{except.terminate} is invoked. +\begin{note} +An implementation is not permitted to reject an expression merely because, when +executed, it throws or might +throw an exception from a function with a non-throwing exception specification. +\end{note} +\begin{example} +\begin{codeblock} +extern void f(); // potentially-throwing + +void g() noexcept { + f(); // valid, even if \tcode{f} throws + throw 42; // valid, effectively a call to \tcode{std::terminate} +} +\end{codeblock} +The call to +\tcode{f} +is well-formed despite the possibility for it to throw an exception. +\end{example} + +\pnum +If no matching handler is found, +the function \tcode{std::terminate} is invoked; +whether or not the stack is unwound before this invocation of +\tcode{std::terminate} +is \impldef{stack unwinding before invocation of +\tcode{std::terminate}}\iref{except.terminate}. + \pnum A handler is considered \defnx{active}{exception handling!handler!active} when initialization is complete for the parameter (if any) of the catch clause. @@ -633,14 +686,6 @@ still active is called the \defnx{currently handled exception}{exception handling!currently handled exception}. -\pnum -If no matching handler is found, -the function \tcode{std::terminate} is invoked; -whether or not the stack is unwound before this invocation of -\tcode{std::terminate} -is \impldef{stack unwinding before invocation of -\tcode{std::terminate}}\iref{except.terminate}. - \pnum Referring to any non-static member or base class of an object in the handler for a @@ -726,7 +771,7 @@ \begin{bnf} \nontermdef{noexcept-specifier}\br \keyword{noexcept} \terminal{(} constant-expression \terminal{)}\br - \keyword{noexcept}\br + \keyword{noexcept} \end{bnf} \pnum @@ -805,33 +850,6 @@ has a non-throwing exception specification. \end{example} -\pnum -\indextext{exception handling!terminate called@\tcode{terminate} called}% -\indextext{\idxcode{terminate}!called}% -Whenever an exception is thrown -and the search for a handler\iref{except.handle} -encounters the outermost block of a function with a -non-throwing exception specification, -the function \tcode{std::terminate} is invoked\iref{except.terminate}. -\begin{note} -An implementation is not permitted to reject an expression merely because, when -executed, it throws or might -throw an exception from a function with a non-throwing exception specification. -\end{note} -\begin{example} -\begin{codeblock} -extern void f(); // potentially-throwing - -void g() noexcept { - f(); // valid, even if \tcode{f} throws - throw 42; // valid, effectively a call to \tcode{std::terminate} -} -\end{codeblock} -The call to -\tcode{f} -is well-formed despite the possibility for it to throw an exception. -\end{example} - \pnum An expression $E$ is \defnx{potentially-throwing}{potentially-throwing!expression} if @@ -848,7 +866,7 @@ (such as an overloaded operator, an allocation function in a \grammarterm{new-expression}, a constructor for a function argument, -or a destructor if $E$ is a full-expression\iref{intro.execution}) +or a destructor) that has a potentially-throwing exception specification, or \item @@ -969,9 +987,7 @@ \item in an expression, the function is selected by overload resolution\iref{over.match,over.over}; -\item the function is odr-used\iref{term.odr.use} or, if it appears in an -unevaluated operand, would be odr-used if the expression were -potentially-evaluated; +\item the function is odr-used\iref{term.odr.use}; \item the exception specification is compared to that of another declaration (e.g., an explicit specialization or an overriding virtual @@ -991,9 +1007,9 @@ \end{itemize} The exception specification of a defaulted function is evaluated as described above only when needed; similarly, the -\grammarterm{noexcept-specifier} of a specialization of a function -template or member function of a class template is instantiated only when -needed. +\grammarterm{noexcept-specifier} of a specialization +of a templated function +is instantiated only when needed. % \indextext{exception specification|)} @@ -1005,8 +1021,10 @@ The function \tcode{std::terminate}\iref{except.terminate} is used by the exception handling mechanism for coping with errors related to the exception handling -mechanism itself. The function -\tcode{std::current_exception()}\iref{propagation} and the class +mechanism itself. +The function \tcode{std::uncaught_exceptions}\iref{uncaught.exceptions} +reports how many exceptions are uncaught in the current thread. +The function \tcode{std::current_exception}\iref{propagation} and the class \tcode{std::nested_exception}\iref{except.nested} can be used by a program to capture the currently handled exception. @@ -1014,9 +1032,10 @@ \pnum \indextext{\idxcode{terminate}}% -% FIXME: What does it mean to abandon exception handling? -In some situations, exception handling is abandoned -for less subtle error handling techniques. +Some errors in a program cannot be recovered from, such as when an exception +is not handled or a \tcode{std::thread} object is destroyed while its thread +function is still executing. In such cases, +the function \tcode{std::terminate}\iref{exception.terminate} is invoked. \begin{note} These situations are: \indextext{\idxcode{terminate}!called}% @@ -1032,9 +1051,14 @@ \item% when the exception handling mechanism cannot find a handler for a thrown exception\iref{except.handle}, or -\item when the search for a handler\iref{except.handle} encounters the -outermost block of a function -with a non-throwing exception specification\iref{except.spec}, or +\item when the search for a handler\iref{except.handle} +exits the function body of a function +with a non-throwing exception specification\iref{except.spec}, +including when a contract-violation handler +invoked from an evaluation of +a function contract assertion\iref{basic.contract.eval} associated with the function +exits via an exception, +or \item% when the destruction of an object during stack unwinding\iref{except.ctor} @@ -1082,7 +1106,27 @@ \item% when a call to a \tcode{wait()}, \tcode{wait_until()}, or \tcode{wait_for()} function on a condition variable\iref{thread.condition.condvar,thread.condition.condvarany} -fails to meet a postcondition. +fails to meet a postcondition, or + +\item% +when a callback invocation exits via an exception +when requesting stop on +a \tcode{std::stop_source} or +a \tcode{std::in\-place_stop_source}\iref{stopsource.mem,stopsource.inplace.mem}, +or in the constructor of +\tcode{std::stop_callback} or +\tcode{std::inplace_stop_callback}\iref{stopcallback.cons,stopcallback.inplace.cons} +when a callback invocation exits via an exception, or + +\item% +when a \tcode{run_loop} object is destroyed +that is still in the \tcode{running} state\iref{exec.run.loop}, or + +\item% +when \tcode{unhandled_stopped} is called on +a \tcode{with_awaitable_senders} object\iref{exec.with.awaitable.senders} +whose continuation is not a handle to a coroutine +whose promise type has an \tcode{unhandled_stopped} member function. \end{itemize} @@ -1090,14 +1134,12 @@ \pnum \indextext{\idxcode{terminate}}% -In such cases, -the function \tcode{std::terminate} is invoked\iref{exception.terminate}. In the situation where no matching handler is found, it is \impldef{stack unwinding before invocation of \tcode{std::terminate}} whether or not the stack is unwound before \tcode{std::terminate} is invoked. -In the situation where the search for a handler\iref{except.handle} encounters the -outermost block of a function +In the situation where the search for a handler\iref{except.handle} +exits the function body of a function with a non-throwing exception specification\iref{except.spec}, it is \impldef{whether stack is unwound before invoking the function \tcode{std::terminate} when a \tcode{noexcept} specification is violated} @@ -1110,21 +1152,4 @@ prematurely based on a determination that the unwind process will eventually cause an invocation of the function \tcode{std::terminate}. - -\rSec2[except.uncaught]{The \tcode{std::uncaught_exceptions} function}% -\indexlibraryglobal{uncaught_exceptions} - -\pnum -An exception is considered uncaught -after completing the initialization of the exception object\iref{except.throw} -until completing the activation of a handler for the exception\iref{except.handle}. -\begin{note} -As a consequence, an exception is considered uncaught -during any stack unwinding resulting from it being thrown. -\end{note} -If an exception is rethrown\iref{expr.throw,propagation}, -it is considered uncaught from the point of rethrow -until the rethrown exception is caught. -The function \tcode{std::uncaught_exceptions}\iref{uncaught.exceptions} -returns the number of uncaught exceptions in the current thread.% \indextext{exception handling|)} diff --git a/source/exec.tex b/source/exec.tex new file mode 100644 index 0000000000..a26e23fc4c --- /dev/null +++ b/source/exec.tex @@ -0,0 +1,5675 @@ +%!TEX root = std.tex +\rSec0[exec]{Execution control library} + +\rSec1[exec.general]{General} + +\pnum +This Clause describes components +supporting execution of function objects\iref{function.objects}. + +\pnum +The following subclauses describe +the requirements, concepts, and components +for execution control primitives as summarized in \tref{exec.summary}. + +\begin{libsumtab}{Execution control library summary}{exec.summary} +\ref{exec.sched} & Schedulers & \tcode{} \\ +\ref{exec.recv} & Receivers & \\ +\ref{exec.opstate} & Operation states & \\ +\ref{exec.snd} & Senders & \\ +\end{libsumtab} + +\pnum +\tref{exec.pos} shows +the types of customization point objects\iref{customization.point.object} +used in the execution control library. + +\begin{floattable}{Types of customization point objects in the execution control library}{exec.pos}{lx{0.23\hsize}x{0.45\hsize}} +\topline +\lhdr{Customization point} & \chdr{Purpose} & \rhdr{Examples} \\ +\lhdr{object type} & & \\ +\capsep +core & + provide core execution functionality, and connection between core components & + e.g., \tcode{connect}, \tcode{start} \\ +completion functions & + called by senders to announce the completion of the work (success, error, or cancellation) & + \tcode{set_value}, \tcode{set_error}, \tcode{set_stopped} \\ +senders & + allow the specialization of the provided sender algorithms & + \begin{itemize} + \item sender factories (e.g., \tcode{schedule}, \tcode{just}, \tcode{read_env}) + \item sender adaptors (e.g., \tcode{continues_on}, \tcode{then}, \tcode{let_value}) + \item sender consumers (e.g., \tcode{sync_wait}) + \end{itemize} + \\ +queries & + allow querying different properties of objects & + \begin{itemize} + \item general queries (e.g., \tcode{get_allocator}, \tcode{get_stop_token}) + \item environment queries (e.g., \tcode{get_scheduler}, \tcode{get_delegation_scheduler}) + \item scheduler queries (e.g., \tcode{get_forward_progress_guarantee}) + \item sender attribute queries (e.g., \tcode{get_completion_scheduler}) + \end{itemize} + \\ +\end{floattable} + +\pnum +This clause makes use of the following exposition-only entities. + +\pnum +For a subexpression \tcode{expr}, +let \tcode{\exposid{MANDATE-NOTHROW}(expr)} be +expression-equivalent to \tcode{expr}. + +\mandates +\tcode{noexcept(expr)} is \tcode{true}. + +\pnum +\begin{codeblock} +namespace std { + template + concept @\defexposconcept{movable-value}@ = // \expos + @\libconcept{move_constructible}@> && + @\libconcept{constructible_from}@, T> && + (!is_array_v>); +} +\end{codeblock} + +\pnum +For function types \tcode{F1} and \tcode{F2} denoting +\tcode{R1(Args1...)} and \tcode{R2(Args2...)}, respectively, +\tcode{\exposid{MATCHING-SIG}(F1, F2)} is \tcode{true} if and only if +\tcode{\libconcept{same_as}} +is \tcode{true}. + +\pnum +For a subexpression \tcode{err}, +let \tcode{Err} be \tcode{decltype((err))} and +let \tcode{\exposid{AS-EXCEPT-PTR}(err)} be: +\begin{itemize} +\item +\tcode{err} if \tcode{decay_t} denotes the type \tcode{exception_ptr}. + +\expects +\tcode{!err} is \tcode{false}. +\item +Otherwise, +\tcode{make_exception_ptr(system_error(err))} +if \tcode{decay_t} denotes the type \tcode{error_code}. +\item +Otherwise, \tcode{make_exception_ptr(err)}. +\end{itemize} + +\pnum +For a subexpression \tcode{expr}, +let \tcode{\exposid{AS-CONST}(expr)} be expression-equivalent to +\begin{codeblock} +[](const auto& x) noexcept -> const auto& { return x; }(expr) +\end{codeblock} + +\rSec1[exec.queryable]{Queries and queryables} + +\rSec2[exec.queryable.general]{General} + +\pnum +A \defnadj{queryable}{object} is +a read-only collection of key/value pair +where each key is a customization point object known as a \defn{query object}. +A \defn{query} is an invocation of a query object +with a queryable object as its first argument and +a (possibly empty) set of additional arguments. +A query imposes syntactic and semantic requirements on its invocations. + +\pnum +Let \tcode{q} be a query object, +let \tcode{args} be a (possibly empty) pack of subexpressions, +let \tcode{env} be a subexpression +that refers to a queryable object \tcode{o} of type \tcode{O}, and +let \tcode{cenv} be a subexpression referring to \tcode{o} +such that \tcode{decltype((cenv))} is \tcode{const O\&}. +The expression \tcode{q(env, args...)} is equal to\iref{concepts.equality} +the expression \tcode{q(cenv, args...)}. + +\pnum +The type of a query expression cannot be \tcode{void}. + +\pnum +The expression \tcode{q(env, args...)} is +equality-preserving\iref{concepts.equality} and +does not modify the query object or the arguments. + +\pnum +If the expression \tcode{env.query(q, args...)} is well-formed, +then it is expression-equivalent to \tcode{q(env, args...)}. + +\pnum +Unless otherwise specified, +the result of a query is valid as long as the queryable object is valid. + +\rSec2[exec.queryable.concept]{\tcode{queryable} concept} + +\begin{codeblock} +namespace std { + template + concept @\defexposconcept{queryable}@ = @\libconcept{destructible}@; // \expos +} +\end{codeblock} + +\pnum +The exposition-only \exposconcept{queryable} concept specifies +the constraints on the types of queryable objects. + +\pnum +Let \tcode{env} be an object of type \tcode{Env}. +The type \tcode{Env} models \exposconcept{queryable} +if for each callable object \tcode{q} and a pack of subexpressions \tcode{args}, +if \tcode{requires \{ q(env, args...) \}} is \tcode{true} then +\tcode{q(env, args...)} meets any semantic requirements imposed by \tcode{q}. + +\rSec1[exec.async.ops]{Asynchronous operations} + +\pnum +An \defnadj{execution}{resource} is a program entity that manages +a (possibly dynamic) set of execution agents\iref{thread.req.lockable.general}, +which it uses to execute parallel work on behalf of callers. +\begin{example} +The currently active thread, +a system-provided thread pool, and +uses of an API associated with an external hardware accelerator +are all examples of execution resources. +\end{example} +Execution resources execute asynchronous operations. +An execution resource is either valid or invalid. + +\pnum +An \defnadj{asynchronous}{operation} is +a distinct unit of program execution that +\begin{itemize} +\item +is explicitly created; +\item +can be explicitly started once at most; +\item +once started, eventually completes exactly once +with a (possibly empty) set of result datums and +in exactly one of three \defnx{dispositions}{disposition}: +success, failure, or cancellation; +\begin{itemize} +\item +A successful completion, also known as a \defnadj{value}{completion}, +can have an arbitrary number of result datums. +\item +A failure completion, also known as an \defnadj{error}{completion}, +has a single result datum. +\item +A cancellation completion, also known as a \defnadj{stopped}{completion}, +has no result datum. +\end{itemize} +An asynchronous operation's \defnadj{async}{result} +is its disposition and its (possibly empty) set of result datums. +\item +can complete on a different execution resource +than the execution resource on which it started; and +\item +can create and start other asynchronous operations +called \defnadj{child}{operations}. +A child operation is an asynchronous operation +that is created by the parent operation and, +if started, completes before the parent operation completes. +A \defnadj{parent}{operation} is the asynchronous operation +that created a particular child operation. +\end{itemize} +\begin{note} +An asynchronous operation can execute synchronously; +that is, it can complete during the execution of its start operation +on the thread of execution that started it. +\end{note} + +\pnum +An asynchronous operation has associated state +known as its \defnadj{operation}{state}. + +\pnum +An asynchronous operation has an associated environment. +An \defn{environment} is a queryable object\iref{exec.queryable} +representing the execution-time properties of the operation's caller. +The caller of an asynchronous operation is +its parent operation or the function that created it. + +\pnum +An asynchronous operation has an associated receiver. +A \defn{receiver} is an aggregation of three handlers +for the three asynchronous completion dispositions: +\begin{itemize} +\item a value completion handler for a value completion, +\item an error completion handler for an error completion, and +\item a stopped completion handler for a stopped completion. +\end{itemize} +A receiver has an associated environment. +An asynchronous operation's operation state owns the operation's receiver. +The environment of an asynchronous operation +is equal to its receiver's environment. + +\pnum +For each completion disposition, there is a \defnadj{completion}{function}. +A completion function is +a customization point object\iref{customization.point.object} +that accepts an asynchronous operation's receiver as the first argument and +the result datums of the asynchronous operation as additional arguments. +The value completion function invokes +the receiver's value completion handler with the value result datums; +likewise for the error completion function and the stopped completion function. +A completion function has +an associated type known as its \defnadj{completion}{tag} +that is the unqualified type of the completion function. +A valid invocation of a completion function is called +a \defnadj{completion}{operation}. + +\pnum +The \defn{lifetime of an asynchronous operation}, +also known as the operation's \defn{async lifetime}, +begins when its start operation begins executing and +ends when its completion operation begins executing. +If the lifetime of an asynchronous operation's associated operation state +ends before the lifetime of the asynchronous operation, +the behavior is undefined. +After an asynchronous operation executes a completion operation, +its associated operation state is invalid. +Accessing any part of an invalid operation state is undefined behavior. + +\pnum +An asynchronous operation shall not execute a completion operation +before its start operation has begun executing. +After its start operation has begun executing, +exactly one completion operation shall execute. +The lifetime of an asynchronous operation's operation state can end +during the execution of the completion operation. + +\pnum +A \defn{sender} is a factory for one or more asynchronous operations. +\defnx{Connecting}{connect} a sender and a receiver creates +an asynchronous operation. +The asynchronous operation's associated receiver is equal to +the receiver used to create it, and +its associated environment is equal to +the environment associated with the receiver used to create it. +The lifetime of an asynchronous operation's associated operation state +does not depend on the lifetimes of either the sender or the receiver +from which it was created. +A sender is started when it is connected to a receiver and +the resulting asynchronous operation is started. +A sender's async result is the async result of the asynchronous operation +created by connecting it to a receiver. +A sender sends its results by way of the asynchronous operation(s) it produces, +and a receiver receives those results. +A sender is either valid or invalid; +it becomes invalid when its parent sender (see below) becomes invalid. + +\pnum +A \defn{scheduler} is an abstraction of an execution resource +with a uniform, generic interface for scheduling work onto that resource. +It is a factory for senders +whose asynchronous operations execute value completion operations +on an execution agent belonging to +the scheduler's associated execution resource. +A \defn{schedule-expression} obtains such a sender from a scheduler. +A \defn{schedule sender} is the result of a schedule expression. +On success, an asynchronous operation produced by a schedule sender executes +a value completion operation with an empty set of result datums. +Multiple schedulers can refer to the same execution resource. +A scheduler can be valid or invalid. +A scheduler becomes invalid when the execution resource to which it refers +becomes invalid, +as do any schedule senders obtained from the scheduler, and +any operation states obtained from those senders. + +\pnum +An asynchronous operation has one or more associated completion schedulers +for each of its possible dispositions. +A \defn{completion scheduler} is a scheduler +whose associated execution resource is used to execute +a completion operation for an asynchronous operation. +A value completion scheduler is a scheduler +on which an asynchronous operation's value completion operation can execute. +Likewise for error completion schedulers and stopped completion schedulers. + +\pnum +A sender has an associated queryable object\iref{exec.queryable} +known as its \defnx{attributes}{attribute} +that describes various characteristics of the sender and +of the asynchronous operation(s) it produces. +For each disposition, +there is a query object for reading the associated completion scheduler +from a sender's attributes; +i.e., a value completion scheduler query object +for reading a sender's value completion scheduler, etc. +If a completion scheduler query is well-formed, +the returned completion scheduler is unique +for that disposition for any asynchronous operation the sender creates. +A schedule sender is required to have a value completion scheduler attribute +whose value is equal to the scheduler that produced the schedule sender. + +\pnum +A \defn{completion signature} is a function type +that describes a completion operation. +An asynchronous operation has a finite set of possible completion signatures +corresponding to the completion operations +that the asynchronous operation potentially evaluates\iref{basic.def.odr}. +For a completion function \tcode{set}, +receiver \tcode{rcvr}, and +pack of arguments \tcode{args}, +let \tcode{c} be the completion operation \tcode{set(rcvr, args...)}, and +let \tcode{F} be +the function type \tcode{decltype(auto(set))(decltype((args))...)}. +A completion signature \tcode{Sig} is associated with \tcode{c} +if and only if +\tcode{\exposid{MATCHING-SIG}(Sig, F)} is \tcode{true}\iref{exec.general}. +Together, a sender type and an environment type \tcode{Env} determine +the set of completion signatures of an asynchronous operation +that results from connecting the sender with a receiver +that has an environment of type \tcode{Env}. +The type of the receiver does not affect +an asynchronous operation's completion signatures, +only the type of the receiver's environment. + +\pnum +A sender algorithm is a function that takes and/or returns a sender. +There are three categories of sender algorithms: +\begin{itemize} +\item +A \defn{sender factory} is a function +that takes non-senders as arguments and that returns a sender. +\item +A \defn{sender adaptor} is a function +that constructs and returns a parent sender +from a set of one or more child senders and +a (possibly empty) set of additional arguments. +An asynchronous operation created by a parent sender is +a parent operation to the child operations created by the child senders. +\item +A \defn{sender consumer} is a function +that takes one or more senders and +a (possibly empty) set of additional arguments, and +whose return type is not the type of a sender. +\end{itemize} + +\rSec1[execution.syn]{Header \tcode{} synopsis} + +\indexheader{execution}% +\begin{codeblock} +namespace std { + // \ref{execpol.type}, execution policy type trait + template struct is_execution_policy; // freestanding + template constexpr bool @\libglobal{is_execution_policy_v}@ = // freestanding + is_execution_policy::value; +} + +namespace std::execution { + // \ref{execpol.seq}, sequenced execution policy + class sequenced_policy; + + // \ref{execpol.par}, parallel execution policy + class parallel_policy; + + // \ref{execpol.parunseq}, parallel and unsequenced execution policy + class parallel_unsequenced_policy; + + // \ref{execpol.unseq}, unsequenced execution policy + class unsequenced_policy; + + // \ref{execpol.objects}, execution policy objects + inline constexpr sequenced_policy seq{ @\unspec@ }; + inline constexpr parallel_policy par{ @\unspec@ }; + inline constexpr parallel_unsequenced_policy par_unseq{ @\unspec@ }; + inline constexpr unsequenced_policy unseq{ @\unspec@ }; +} + +namespace std { + // \ref{exec.general}, helper concepts + template + concept @\exposconceptnc{movable-value}@ = @\seebelownc@; // \expos + + template + concept @\defexposconceptnc{decays-to}@ = @\libconcept{same_as}@, To>; // \expos + + template + concept @\defexposconceptnc{class-type}@ = @\exposconceptnc{decays-to}@ && is_class_v; // \expos + + // \ref{exec.queryable}, queryable objects + template + concept @\exposconceptnc{queryable}@ = @\seebelownc@; // \expos + + // \ref{exec.queries}, queries + struct @\libglobal{forwarding_query_t}@ { @\unspec@ }; + struct @\libglobal{get_allocator_t}@ { @\unspec@ }; + struct @\libglobal{get_stop_token_t}@ { @\unspec@ }; + + inline constexpr forwarding_query_t @\libglobal{forwarding_query}@{}; + inline constexpr get_allocator_t @\libglobal{get_allocator}@{}; + inline constexpr get_stop_token_t @\libglobal{get_stop_token}@{}; + + template + using stop_token_of_t = remove_cvref_t()))>; + + template + concept @\defexposconceptnc{forwarding-query}@ = forwarding_query(T{}); // \expos +} + +namespace std::execution { + // \ref{exec.queries}, queries + struct @\libglobal{get_domain_t}@ { @\unspec@ }; + struct @\libglobal{get_scheduler_t}@ { @\unspec@ }; + struct @\libglobal{get_delegation_scheduler_t}@ { @\unspec@ }; + struct @\libglobal{get_forward_progress_guarantee_t}@ { @\unspec@ }; + template + struct @\libglobal{get_completion_scheduler_t}@ { @\unspec@ }; + + inline constexpr get_domain_t @\libglobal{get_domain}@{}; + inline constexpr get_scheduler_t @\libglobal{get_scheduler}@{}; + inline constexpr get_delegation_scheduler_t @\libglobal{get_delegation_scheduler}@{}; + enum class forward_progress_guarantee; + inline constexpr get_forward_progress_guarantee_t @\libglobal{get_forward_progress_guarantee}@{}; + template + constexpr get_completion_scheduler_t @\libglobal{get_completion_scheduler}@{}; + + struct @\libglobal{get_env_t}@ { @\unspec@ }; + inline constexpr get_env_t @\libglobal{get_env}@{}; + + template + using @\libglobal{env_of_t}@ = decltype(get_env(declval())); + + // \ref{exec.prop}, class template \tcode{prop} + template + struct prop; + + // \ref{exec.env}, class template \tcode{env} + template<@\exposconcept{queryable}@... Envs> + struct env; + + // \ref{exec.domain.default}, execution domains + struct default_domain; + + // \ref{exec.sched}, schedulers + struct @\libglobal{scheduler_t}@ {}; + + template + concept @\libconcept{scheduler}@ = @\seebelow@; + + // \ref{exec.recv}, receivers + struct @\libglobal{receiver_t}@ {}; + + template + concept @\libconcept{receiver}@ = @\seebelow@; + + template + concept @\libconcept{receiver_of}@ = @\seebelow@; + + struct @\libglobal{set_value_t}@ { @\unspec@ }; + struct @\libglobal{set_error_t}@ { @\unspec@ }; + struct @\libglobal{set_stopped_t}@ { @\unspec@ }; + + inline constexpr set_value_t @\libglobal{set_value}@{}; + inline constexpr set_error_t @\libglobal{set_error}@{}; + inline constexpr set_stopped_t @\libglobal{set_stopped}@{}; + + // \ref{exec.opstate}, operation states + struct @\libglobal{operation_state_t}@ {}; + + template + concept @\libconcept{operation_state}@ = @\seebelow@; + + struct @\libglobal{start_t}@; + inline constexpr start_t @\libglobal{start}@{}; + + // \ref{exec.snd}, senders + struct @\libglobal{sender_t}@ {}; + + template + concept @\libconcept{sender}@ = @\seebelow@; + + template> + concept @\libconcept{sender_in}@ = @\seebelow@; + + template + concept @\libconcept{sender_to}@ = @\seebelow@; + + template + struct @\exposidnc{type-list}@; // \expos + + // \ref{exec.getcomplsigs}, completion signatures + struct get_completion_signatures_t; + inline constexpr get_completion_signatures_t get_completion_signatures {}; + + template> + requires @\libconcept{sender_in}@ + using completion_signatures_of_t = @\exposid{call-result-t}@; + + template + using @\exposidnc{decayed-tuple}@ = tuple...>; // \expos + + template + using @\exposidnc{variant-or-empty}@ = @\seebelownc@; // \expos + + template, + template class Tuple = @\exposid{decayed-tuple}@, + template class Variant = @\exposid{variant-or-empty}@> + requires @\libconcept{sender_in}@ + using value_types_of_t = @\seebelow@; + + template, + template class Variant = @\exposid{variant-or-empty}@> + requires @\libconcept{sender_in}@ + using error_types_of_t = @\seebelow@; + + template> + requires @\libconcept{sender_in}@ + constexpr bool sends_stopped = @\seebelow@; + + template + using @\exposidnc{single-sender-value-type}@ = @\seebelownc@; // \expos + + template + concept @\exposconcept{single-sender}@ = @\seebelow@; // \expos + + template<@\libconcept{sender}@ Sndr> + using tag_of_t = @\seebelow@; + + // \ref{exec.snd.transform}, sender transformations + template + requires (sizeof...(Env) <= 1) + constexpr @\libconcept{sender}@ decltype(auto) transform_sender( + Domain dom, Sndr&& sndr, const Env&... env) noexcept(@\seebelow@); + + // \ref{exec.snd.transform.env}, environment transformations + template + constexpr @\exposconcept{queryable}@ decltype(auto) transform_env( + Domain dom, Sndr&& sndr, Env&& env) noexcept; + + // \ref{exec.snd.apply}, sender algorithm application + template + constexpr decltype(auto) apply_sender( + Domain dom, Tag, Sndr&& sndr, Args&&... args) noexcept(@\seebelow@); + + // \ref{exec.connect}, the connect sender algorithm + struct @\libglobal{connect_t}@; + inline constexpr connect_t @\libglobal{connect}@{}; + + template + using @\libglobal{connect_result_t}@ = + decltype(connect(declval(), declval())); + + // \ref{exec.factories}, sender factories + struct @\libglobal{just_t}@ { @\unspec@ }; + struct @\libglobal{just_error_t}@ { @\unspec@ }; + struct @\libglobal{just_stopped_t}@ { @\unspec@ }; + struct @\libglobal{schedule_t}@ { @\unspec@ }; + + inline constexpr just_t @\libglobal{just}@{}; + inline constexpr just_error_t @\libglobal{just_error}@{}; + inline constexpr just_stopped_t @\libglobal{just_stopped}@{}; + inline constexpr schedule_t @\libglobal{schedule}@{}; + inline constexpr @\unspec@ @\libglobal{read_env}@{}; + + template<@\libconcept{scheduler}@ Sndr> + using @\libglobal{schedule_result_t}@ = decltype(schedule(declval())); + + // \ref{exec.adapt}, sender adaptors + template<@\exposconcept{class-type}@ D> + struct @\libglobal{sender_adaptor_closure}@ { }; + + struct @\libglobal{starts_on_t}@ { @\unspec@ }; + struct @\libglobal{continues_on_t}@ { @\unspec@ }; + struct @\libglobal{on_t}@ { @\unspec@ }; + struct @\libglobal{schedule_from_t}@ { @\unspec@ }; + struct @\libglobal{then_t}@ { @\unspec@ }; + struct @\libglobal{upon_error_t}@ { @\unspec@ }; + struct @\libglobal{upon_stopped_t}@ { @\unspec@ }; + struct @\libglobal{let_value_t}@ { @\unspec@ }; + struct @\libglobal{let_error_t}@ { @\unspec@ }; + struct @\libglobal{let_stopped_t}@ { @\unspec@ }; + struct @\libglobal{bulk_t}@ { @\unspec@ }; + struct @\libglobal{split_t}@ { @\unspec@ }; + struct @\libglobal{when_all_t}@ { @\unspec@ }; + struct @\libglobal{when_all_with_variant_t}@ { @\unspec@ }; + struct @\libglobal{into_variant_t}@ { @\unspec@ }; + struct @\libglobal{stopped_as_optional_t}@ { @\unspec@ }; + struct @\libglobal{stopped_as_error_t}@ { @\unspec@ }; + + inline constexpr starts_on_t @\libglobal{starts_on}@{}; + inline constexpr continues_on_t @\libglobal{continues_on}@{}; + inline constexpr on_t @\libglobal{on}@{}; + inline constexpr schedule_from_t @\libglobal{schedule_from}@{}; + inline constexpr then_t @\libglobal{then}@{}; + inline constexpr upon_error_t @\libglobal{upon_error}@{}; + inline constexpr upon_stopped_t @\libglobal{upon_stopped}@{}; + inline constexpr let_value_t @\libglobal{let_value}@{}; + inline constexpr let_error_t @\libglobal{let_error}@{}; + inline constexpr let_stopped_t @\libglobal{let_stopped}@{}; + inline constexpr bulk_t @\libglobal{bulk}@{}; + inline constexpr split_t @\libglobal{split}@{}; + inline constexpr when_all_t @\libglobal{when_all}@{}; + inline constexpr when_all_with_variant_t @\libglobal{when_all_with_variant}@{}; + inline constexpr into_variant_t @\libglobal{into_variant}@{}; + inline constexpr stopped_as_optional_t @\libglobal{stopped_as_optional}@{}; + inline constexpr stopped_as_error_t @\libglobal{stopped_as_error}@{}; + + // \ref{exec.util}, sender and receiver utilities + // \ref{exec.util.cmplsig} + template + concept @\exposconceptnc{completion-signature}@ = @\seebelownc@; // \expos + + template<@\exposconcept{completion-signature}@... Fns> + struct @\libglobal{completion_signatures}@ {}; + + template + concept @\exposconceptnc{valid-completion-signatures}@ = @\seebelownc@; // \expos + + // \ref{exec.util.cmplsig.trans} + template< + @\exposconcept{valid-completion-signatures}@ InputSignatures, + @\exposconcept{valid-completion-signatures}@ AdditionalSignatures = completion_signatures<>, + template class SetValue = @\seebelow@, + template class SetError = @\seebelow@, + @\exposconcept{valid-completion-signatures}@ SetStopped = completion_signatures> + using transform_completion_signatures = completion_signatures<@\seebelow@>; + + template< + @\libconcept{sender}@ Sndr, + class Env = env<>, + @\exposconcept{valid-completion-signatures}@ AdditionalSignatures = completion_signatures<>, + template class SetValue = @\seebelow@, + template class SetError = @\seebelow@, + @\exposconcept{valid-completion-signatures}@ SetStopped = completion_signatures> + requires @\libconcept{sender_in}@ + using transform_completion_signatures_of = + transform_completion_signatures< + completion_signatures_of_t, + AdditionalSignatures, SetValue, SetError, SetStopped>; + + // \ref{exec.run.loop}, run_loop + class run_loop; +} + +namespace std::this_thread { + // \ref{exec.consumers}, consumers + struct @\libglobal{sync_wait_t}@ { @\unspec@ }; + struct @\libglobal{sync_wait_with_variant_t}@ { @\unspec@ }; + + inline constexpr sync_wait_t @\libglobal{sync_wait}@{}; + inline constexpr sync_wait_with_variant_t @\libglobal{sync_wait_with_variant}@{}; +} + +namespace std::execution { + // \ref{exec.as.awaitable} + struct @\libglobal{as_awaitable_t}@ { @\unspec@ }; + inline constexpr as_awaitable_t @\libglobal{as_awaitable}@{}; + + // \ref{exec.with.awaitable.senders} + template<@\exposconcept{class-type}@ Promise> + struct with_awaitable_senders; +} +\end{codeblock} + +\pnum +The exposition-only type \tcode{\exposid{variant-or-empty}} +is defined as follows: +\begin{itemize} +\item +If \tcode{sizeof...(Ts)} is greater than zero, +\tcode{\exposid{variant-or-empty}} denotes \tcode{variant} +where \tcode{Us...} is the pack \tcode{decay_t...} +with duplicate types removed. +\item +Otherwise, \tcode{\exposid{variant-or-empty}} denotes +the exposition-only class type: +\begin{codeblock} +namespace std::execution { + struct @\exposidnc{empty-variant}@ { // \expos + @\exposidnc{empty-variant}@() = delete; + }; +} +\end{codeblock} +\end{itemize} + +\pnum +For types \tcode{Sndr} and \tcode{Env}, +\tcode{\exposid{single-sender-value-type}} is an alias for: +\begin{itemize} +\item +\tcode{value_types_of_t} +if that type is well-formed, +\item +Otherwise, \tcode{void} +if \tcode{value_types_of_t} is +\tcode{variant>} or \tcode{vari\-ant<>}, +\item +Otherwise, \tcode{value_types_of_t} +if that type is well-formed, +\item +Otherwise, \tcode{\exposid{single-sender-value-type}} is ill-formed. +\end{itemize} + +\pnum +The exposition-only concept \exposconcept{single-sender} is defined as follows: +\begin{codeblock} +namespace std::execution { + template + concept @\defexposconcept{single-sender}@ = @\libconcept{sender_in}@ && + requires { + typename @\exposid{single-sender-value-type}@; + }; +} +\end{codeblock} + +\rSec1[exec.queries]{Queries} + +\rSec2[exec.fwd.env]{\tcode{forwarding_query}} + +\pnum +\tcode{forwarding_query} asks a query object +whether it should be forwarded through queryable adaptors. + +\pnum +The name \tcode{forwarding_query} denotes a query object. +For some query object \tcode{q} of type \tcode{Q}, +\tcode{forwarding_query(q)} is expression-equivalent to: +\begin{itemize} +\item +\tcode{\exposid{MANDATE-NOTHROW}(q.query(forwarding_query))} +if that expression is well-formed. + +\mandates +The expression above has type \tcode{bool} and +is a core constant expression if \tcode{q} is a core constant expression. +\item +Otherwise, \tcode{true} if \tcode{\libconcept{derived_from}} is \tcode{true}. +\item +Otherwise, \tcode{false}. +\end{itemize} + +\rSec2[exec.get.allocator]{\tcode{get_allocator}} + +\pnum +\tcode{get_allocator} asks a queryable object for its associated allocator. + +\pnum +The name \tcode{get_allocator} denotes a query object. +For a subexpression \tcode{env}, +\tcode{get_allocator(env)} is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_allocator))}. + +\mandates +If the expression above is well-formed, +its type satisfies +\exposconcept{simple-allocator}\iref{allocator.requirements.general}. + +\pnum +\tcode{forwarding_query(get_allocator)} is a core constant expression and +has value \tcode{true}. + +\rSec2[exec.get.stop.token]{\tcode{get_stop_token}} + +\pnum +\tcode{get_stop_token} asks a queryable object for an associated stop token. + +\pnum +The name \tcode{get_stop_token} denotes a query object. +For a subexpression \tcode{env}, +\tcode{get_stop_token(env)} is expression-equivalent to: +\begin{itemize} +\item +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_stop_token))} +if that expression is well-formed. + +\mandates +The type of the expression above satisfies \libconcept{stoppable_token}. + +\item +Otherwise, \tcode{never_stop_token\{\}}. +\end{itemize} + +\pnum +\tcode{forwarding_query(get_stop_token)} is a core constant expression and +has value \tcode{true}. + +\rSec2[exec.get.env]{\tcode{execution::get_env}} + +\pnum +\tcode{execution::get_env} is a customization point object. +For a subexpression \tcode{o}, +\tcode{execution::get_env(o)} is expression-equivalent to: +\begin{itemize} +\item +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(o).get_env())} +if that expression is well-formed. + +\mandates +The type of the expression above satisfies +\exposconcept{queryable}\iref{exec.queryable}. +\item +Otherwise, \tcode{env<>\{\}}. +\end{itemize} + +\pnum +The value of \tcode{get_env(o)} shall be valid while \tcode{o} is valid. + +\pnum +\begin{note} +When passed a sender object, +\tcode{get_env} returns the sender's associated attributes. +When passed a receiver, +\tcode{get_env} returns the receiver's associated execution environment. +\end{note} + +\rSec2[exec.get.domain]{\tcode{execution::get_domain}} + +\pnum +\tcode{get_domain} asks a queryable object +for its associated execution domain tag. + +\pnum +The name \tcode{get_domain} denotes a query object. +For a subexpression \tcode{env}, +\tcode{get_domain(env)} is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_domain))}. + +\pnum +\tcode{forwarding_query(execution::get_domain)} is +a core constant expression and has value \tcode{true}. + +\rSec2[exec.get.scheduler]{\tcode{execution::get_scheduler}} + +\pnum +\tcode{get_scheduler} asks a queryable object for its associated scheduler. + +\pnum +The name \tcode{get_scheduler} denotes a query object. +For a subexpression \tcode{env}, +\tcode{get_scheduler(env)} is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_scheduler))}. + +\mandates +If the expression above is well-formed, +its type satisfies \libconcept{scheduler}. + +\pnum +\tcode{forwarding_query(execution::get_scheduler)} is +a core constant expression and has value \tcode{true}. + +\rSec2[exec.get.delegation.scheduler]{\tcode{execution::get_delegation_scheduler}} + +\pnum +\tcode{get_delegation_scheduler} asks a queryable object for a scheduler +that can be used to delegate work to +for the purpose of forward progress delegation\iref{intro.progress}. + +\pnum +The name \tcode{get_delegation_scheduler} denotes a query object. +For a subexpression \tcode{env}, +\tcode{get_delegation_scheduler(env)} is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_delegation_scheduler))}. + +\mandates +If the expression above is well-formed, +its type satisfies \libconcept{scheduler}. + +\pnum +\tcode{forwarding_query(execution::get_delegation_scheduler)} is +a core constant expression and has value \tcode{true}. + +\rSec2[exec.get.fwd.progress]{\tcode{execution::get_forward_progress_guarantee}} + +\begin{codeblock} +namespace std::execution { + enum class @\libglobal{forward_progress_guarantee}@ { + concurrent, + parallel, + weakly_parallel + }; +} +\end{codeblock} + +\pnum +\tcode{get_forward_progress_guarantee} asks a scheduler about +the forward progress guarantee of execution agents +created by that scheduler's associated execution resource\iref{intro.progress}. + +\pnum +The name \tcode{get_forward_progress_guarantee} denotes a query object. +For a subexpression \tcode{sch}, let \tcode{Sch} be \tcode{decltype((sch))}. +If \tcode{Sch} does not satisfy \libconcept{scheduler}, +\tcode{get_forward_progress_guarantee} is ill-formed. +Otherwise, +\tcode{get_forward_progress_guarantee(sch)} is expression-equivalent to: +\begin{itemize} +\item +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(sch).query(get_forward_progress_guarantee))}, +if that expression is well-formed. + +\mandates +The type of the expression above is \tcode{forward_progress_guarantee}. +\item +Otherwise, \tcode{forward_progress_guarantee::weakly_parallel}. +\end{itemize} + +\pnum +If \tcode{get_forward_progress_guarantee(sch)} for some scheduler \tcode{sch} +returns \tcode{forward_progress_guaran\-tee::concurrent}, +all execution agents created by that scheduler's associated execution resource +shall provide the concurrent forward progress guarantee. +If it returns \tcode{forward_progress_guarantee::parallel}, +all such execution agents +shall provide at least the parallel forward progress guarantee. + +\rSec2[exec.get.compl.sched]{\tcode{execution::get_completion_scheduler}} + +\pnum +\tcode{get_completion_scheduler<\exposid{completion-tag>}} obtains +the completion scheduler associated with a completion tag +from a sender's attributes. + +\pnum +The name \tcode{get_completion_scheduler} denotes a query object template. +For a subexpression \tcode{q}, +the expression \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)} +is ill-formed if \exposid{completion-tag} is not one of +\tcode{set_value_t}, \tcode{set_error_t}, or \tcode{set_stopped_t}. +Otherwise, \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)} +is expression-equivalent to +\begin{codeblock} +@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(q).query(get_completion_scheduler<@\exposid{completion-tag}@>)) +\end{codeblock} +\mandates +If the expression above is well-formed, +its type satisfies \libconcept{scheduler}. + +\pnum +Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; +let \exposid{completion-tag} be +the associated completion tag of \exposid{completion-fn}; +let \tcode{args} be a pack of subexpressions; and +let \tcode{sndr} be a subexpression +such that \tcode{\libconcept{sender}} is \tcode{true} and +\tcode{get_completion_scheduler<\exposid{completion-tag}>(get_env(sndr))} +is well-formed and denotes a scheduler \tcode{sch}. +If an asynchronous operation +created by connecting \tcode{sndr} with a receiver \tcode{rcvr} +causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)}, +the behavior is undefined +unless the evaluation happens on an execution agent +that belongs to \tcode{sch}'s associated execution resource. + +\pnum +The expression +\tcode{forwarding_query(get_completion_scheduler<\exposid{completion-tag}>)} +is a core constant expression and has value \tcode{true}. + +\rSec1[exec.sched]{Schedulers} + +\pnum +The \libconcept{scheduler} concept defines +the requirements of a scheduler type\iref{exec.async.ops}. +\tcode{schedule} is a customization point object +that accepts a scheduler. +A valid invocation of \tcode{schedule} is a schedule-expression. +\begin{codeblock} +namespace std::execution { + template + concept @\deflibconcept{scheduler}@ = + @\libconcept{derived_from}@::scheduler_concept, scheduler_t> && + @\exposconcept{queryable}@ && + requires(Sch&& sch) { + { schedule(std::forward(sch)) } -> @\libconcept{sender}@; + { auto(get_completion_scheduler( + get_env(schedule(std::forward(sch))))) } + -> @\libconcept{same_as}@>; + } && + @\libconcept{equality_comparable}@> && + @\libconcept{copyable}@>; +} +\end{codeblock} + +\pnum +Let \tcode{Sch} be the type of a scheduler and +let \tcode{Env} be the type of an execution environment +for which \tcode{\libconcept{sender_in}, Env>} +is satisfied. +Then \tcode{\exposconcept{sender-in-of}, Env>} +shall be modeled. + +\pnum +No operation required by +\tcode{\libconcept{copyable}>} and +\tcode{\libconcept{equality_comparable}>} +shall exit via an exception. +None of these operations, +nor a scheduler type's \tcode{schedule} function, +shall introduce data races +as a result of potentially concurrent\iref{intro.races} invocations +of those operations from different threads. + +\pnum +For any two values \tcode{sch1} and \tcode{sch2} +of some scheduler type \tcode{Sch}, +\tcode{sch1 == sch2} shall return \tcode{true} +only if both \tcode{sch1} and \tcode{sch2} share +the same associated execution resource. + +\pnum +For a given scheduler expression \tcode{sch}, +the expression +\tcode{get_completion_scheduler(get_env(schedule(sch)))} +shall compare equal to \tcode{sch}. + +\pnum +For a given scheduler expression \tcode{sch}, +if the expression \tcode{get_domain(sch)} is well-formed, +then the expression \tcode{get_domain(get_env(schedule(sch)))} +is also well-formed and has the same type. + +\pnum +A scheduler type's destructor shall not block +pending completion of any receivers +connected to the sender objects returned from \tcode{schedule}. +\begin{note} +The ability to wait for completion of submitted function objects +can be provided by the associated execution resource of the scheduler. +\end{note} + +\rSec1[exec.recv]{Receivers} + +\rSec2[exec.recv.concepts]{Receiver concepts} + +\pnum +A receiver represents the continuation of an asynchronous operation. +The \libconcept{receiver} concept defines +the requirements for a receiver type\iref{exec.async.ops}. +The \libconcept{receiver_of} concept defines +the requirements for a receiver type that is usable as +the first argument of a set of completion operations +corresponding to a set of completion signatures. +The \tcode{get_env} customization point object is used to access +a receiver's associated environment. +\begin{codeblock} +namespace std::execution { + template + concept @\deflibconcept{receiver}@ = + @\libconcept{derived_from}@::receiver_concept, receiver_t> && + requires(const remove_cvref_t& rcvr) { + { get_env(rcvr) } -> @\exposconcept{queryable}@; + } && + @\libconcept{move_constructible}@> && // rvalues are movable, and + @\libconcept{constructible_from}@, Rcvr>; // lvalues are copyable + + template + concept @\defexposconcept{valid-completion-for}@ = // \expos + requires (Signature* sig) { + [](Tag(*)(Args...)) + requires @\exposconcept{callable}@, Args...> + {}(sig); + }; + + template + concept @\defexposconcept{has-completions}@ = // \expos + requires (Completions* completions) { + []<@\exposconcept{valid-completion-for}@...Sigs>(completion_signatures*) + {}(completions); + }; + + template + concept @\deflibconcept{receiver_of}@ = + @\libconcept{receiver}@ && @\exposconcept{has-completions}@; +} +\end{codeblock} + +\pnum +Class types that are marked \tcode{final} do not model the \libconcept{receiver} concept. + +\pnum +Let \tcode{rcvr} be a receiver and +let \tcode{op_state} be an operation state associated with +an asynchronous operation created by connecting \tcode{rcvr} with a sender. +Let \tcode{token} be a stop token equal to +\tcode{get_stop_token(get_env(rcvr))}. +\tcode{token} shall remain valid +for the duration of the asynchronous operation's lifetime\iref{exec.async.ops}. +\begin{note} +This means that, unless it knows about further guarantees +provided by the type of \tcode{rcvr}, +the implementation of \tcode{op_state} cannot use \tcode{token} +after it executes a completion operation. +This also implies that any stop callbacks registered on token +must be destroyed before the invocation of the completion operation. +\end{note} + +\rSec2[exec.set.value]{\tcode{execution::set_value}} + +\pnum +\tcode{set_value} is a value completion function\iref{exec.async.ops}. +Its associated completion tag is \tcode{set_value_t}. +The expression \tcode{set_value(rcvr, vs...)} +for a subexpression \tcode{rcvr} and +pack of subexpressions \tcode{vs} is ill-formed +if \tcode{rcvr} is an lvalue or an rvalue of const type. +Otherwise, it is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_value(vs...))}. + +\rSec2[exec.set.error]{\tcode{execution::set_error}} + +\pnum +\tcode{set_error} is an error completion function\iref{exec.async.ops}. +Its associated completion tag is \tcode{set_error_t}. +The expression \tcode{set_error(rcvr, err)} +for some \tcode{subexpressions} \tcode{rcvr} and \tcode{err} is ill-formed +if \tcode{rcvr} is an lvalue or an rvalue of const type. +Otherwise, it is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_error(err))}. + +\rSec2[exec.set.stopped]{\tcode{execution::set_stopped}} + +\pnum +\tcode{set_stopped} is a stopped completion function\iref{exec.async.ops}. +Its associated completion tag is \tcode{set_stopped_t}. +The expression \tcode{set_stopped(rcvr)} +for a subexpression \tcode{rcvr} is ill-formed +if \tcode{rcvr} is an lvalue or an rvalue of const type. +Otherwise, it is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_stopped())}. + +\rSec1[exec.opstate]{Operation states} + +\rSec2[exec.opstate.general]{General} + +\pnum +The \libconcept{operation_state} concept defines +the requirements of an operation state type\iref{exec.async.ops}. +\begin{codeblock} +namespace std::execution { + template + concept @\deflibconcept{operation_state}@ = + @\libconcept{derived_from}@ && + is_object_v && + requires (O& o) { + { start(o) } noexcept; + }; +} +\end{codeblock} + +\pnum +If an \libconcept{operation_state} object is destroyed +during the lifetime of its asynchronous operation\iref{exec.async.ops}, +the behavior is undefined. +\begin{note} +The \libconcept{operation_state} concept does not impose requirements +on any operations other than destruction and \tcode{start}, +including copy and move operations. +Invoking any such operation on an object +whose type models \libconcept{operation_state} can lead to undefined behavior. +\end{note} + +\pnum +The program is ill-formed +if it performs a copy or move construction or assignment operation on +an operation state object created by connecting a library-provided sender. + +\rSec2[exec.opstate.start]{\tcode{execution::start}} + +\pnum +The name \tcode{start} denotes a customization point object +that starts\iref{exec.async.ops} +the asynchronous operation associated with the operation state object. +For a subexpression \tcode{op}, +the expression \tcode{start(op)} is ill-formed +if \tcode{op} is an rvalue. +Otherwise, it is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(op.start())}. + +\pnum +If \tcode{op.start()} does not start\iref{exec.async.ops} +the asynchronous operation associated with the operation state \tcode{op}, +the behavior of calling \tcode{start(op)} is undefined. + +\rSec1[exec.snd]{Senders} + +\rSec2[exec.snd.general]{General} + +\pnum +Subclauses \ref{exec.factories} and \ref{exec.adapt} define +customizable algorithms that return senders. +Each algorithm has a default implementation. +Let \tcode{sndr} be the result of an invocation of such an algorithm or +an object equal to the result\iref{concepts.equality}, and +let \tcode{Sndr} be \tcode{decltype((sndr))}. +Let \tcode{rcvr} be a receiver of type \tcode{Rcvr} +with associated environment \tcode{env} of type \tcode{Env} +such that \tcode{\libconcept{sender_to}} is \tcode{true}. +For the default implementation of the algorithm that produced \tcode{sndr}, +connecting \tcode{sndr} to \tcode{rcvr} and +starting the resulting operation state\iref{exec.async.ops} +necessarily results in the potential evaluation\iref{basic.def.odr} of +a set of completion operations +whose first argument is a subexpression equal to \tcode{rcvr}. +Let \tcode{Sigs} be a pack of completion signatures corresponding to +this set of completion operations. +Then the type of the expression \tcode{get_completion_signatures(sndr, env)} is +a specialization of +the class template \tcode{completion_signatures}\iref{exec.util.cmplsig}, +the set of whose template arguments is \tcode{Sigs}. +If a user-provided implementation of the algorithm +that produced \tcode{sndr} is selected instead of the default, +any completion signature +that is in the set of types +denoted by \tcode{completion_signatures_of_t} and +that is not part of \tcode{Sigs} shall correspond to +error or stopped completion operations, +unless otherwise specified. + +\rSec2[exec.snd.expos]{Exposition-only entities} + +\pnum +Subclause \ref{exec.snd} makes use of the following exposition-only entities. + +\pnum +For a queryable object \tcode{env}, +\tcode{\exposid{FWD-ENV}(env)} is an expression +whose type satisfies \exposconcept{queryable} +such that for a query object \tcode{q} and +a pack of subexpressions \tcode{as}, +the expression \tcode{\exposid{FWD-ENV}(env).query(q, as...)} is ill-formed +if \tcode{forwarding_query(q)} is \tcode{false}; +otherwise, it is expression-equivalent to \tcode{env.query(q, as...)}. + +\pnum +For a query object \tcode{q} and \tcode{a} subexpression \tcode{v}, +\tcode{\exposid{MAKE-ENV}(q, v)} is an expression \tcode{env} +whose type satisfies \exposconcept{queryable} +such that the result of \tcode{env.query(q)} has +a value equal to \tcode{v}\iref{concepts.equality}. +Unless otherwise stated, +the object to which \tcode{env.query(q)} refers remains valid +while \tcode{env} remains valid. + +\pnum +For two queryable objects \tcode{env1} and \tcode{env2}, +a query object \tcode{q}, and +a pack of subexpressions \tcode{as}, +\tcode{\exposid{JOIN-ENV}(env1, env2)} is an expression \tcode{env3} +whose type satisfies \exposconcept{queryable} +such that \tcode{env3.query(q, as...)} is expression-equivalent to: +\begin{itemize} +\item +\tcode{env1.query(q, as...)} if that expression is well-formed, +\item +otherwise, \tcode{env2.query(q, as...)} if that expression is well-formed, +\item +otherwise, \tcode{env3.query(q, as...)} is ill-formed. +\end{itemize} + +\pnum +The results of \exposid{FWD-ENV}, \exposid{MAKE-ENV}, and \exposid{JOIN-ENV} +can be context-dependent; +i.e., they can evaluate to expressions +with different types and value categories +in different contexts for the same arguments. + +\pnum +For a scheduler \tcode{sch}, +\tcode{\exposid{SCHED-ATTRS}(sch)} is an expression \tcode{o1} +whose type satisfies \exposconcept{queryable} +such that \tcode{o1.query(get_completion_scheduler)} is +an expression with the same type and value as \tcode{sch} +where \tcode{Tag} is one of \tcode{set_value_t} or \tcode{set_stopped_t}, and +such that \tcode{o1.query(get_domain)} is expression-equivalent to +\tcode{sch.query(get_domain)}. +\tcode{\exposid{SCHED-ENV}(sch)} is an expression \tcode{o2} +whose type satisfies \exposconcept{queryable} +such that \tcode{o2.query(get_scheduler)} is a prvalue +with the same type and value as \tcode{sch}, and +such that \tcode{o2.query(get_domain)} is expression-equivalent to +\tcode{sch.query(get_domain)}. + +\pnum +For two subexpressions \tcode{rcvr} and \tcode{expr}, +\tcode{\exposid{SET-VALUE}(rcvr, expr)} is expression-equivalent to +\tcode{(expr, set_value(std::move(rcvr)))} +if the type of \tcode{expr} is \tcode{void}; +otherwise, \tcode{set_value(std::move(rcvr), expr)}. +\tcode{\exposid{TRY-EVAL}(rcvr, expr)} is equivalent to: +\begin{codeblock} +try { + expr; +} catch(...) { + set_error(std::move(rcvr), current_exception()); +} +\end{codeblock} +if \tcode{expr} is potentially-throwing; otherwise, \tcode{expr}. +\tcode{\exposid{TRY-SET-VALUE}(rcvr, expr)} is +\begin{codeblock} +@\exposid{TRY-EVAL}@(rcvr, @\exposid{SET-VALUE}@(rcvr, expr)) +\end{codeblock} +except that \tcode{rcvr} is evaluated only once. + +\begin{itemdecl} +template + constexpr auto @\exposid{completion-domain}@(const Sndr& sndr) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{\exposid{COMPL-DOMAIN}(T)} is the type of the expression +\tcode{get_domain(get_completion_scheduler(get_env(sndr)))}. + +\pnum +\effects +If all of the types +\tcode{\exposid{COMPL-DOMAIN}(set_value_t)}, +\tcode{\exposid{COMPL-DOMAIN}(set_error_t)}, and\linebreak +\tcode{\exposid{COMPL-DOMAIN}(set_stopped_t)} are ill-formed, +\tcode{completion-domain(sndr)} is +a default-constructed prvalue of type \tcode{Default}. +Otherwise, if they all share a common type\iref{meta.trans.other} +(ignoring those types that are ill-formed), +then \tcode{\exposid{completion-domain}(sndr)} is +a default-constructed prvalue of that type. +Otherwise, \tcode{\exposid{completion-domain}(sndr)} is ill-formed. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr decltype(auto) @\exposid{query-with-default}@( + Tag, const Env& env, Default&& value) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{e} be the expression \tcode{Tag()(env)} +if that expression is well-formed; +otherwise, it is \tcode{static_cast(std::forward(value))}. + +\pnum +\returns +\tcode{e}. + +\pnum +\remarks +The expression in the noexcept clause is \tcode{noexcept(e)}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr auto @\exposid{get-domain-early}@(const Sndr& sndr) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return Domain(); +\end{codeblock} +where \tcode{Domain} is +the decayed type of the first of the following expressions that is well-formed: +\begin{itemize} +\item \tcode{get_domain(get_env(sndr))} +\item \tcode{\exposid{completion-domain}(sndr)} +\item \tcode{default_domain()} +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr auto @\exposid{get-domain-late}@(const Sndr& sndr, const Env& env) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{itemize} +\item +If \tcode{\exposconcept{sender-for}} is \tcode{true}, then +\begin{codeblock} +return Domain(); +\end{codeblock} +where \tcode{Domain} is the type of the following expression: +\begin{codeblock} +[] { + auto [_, sch, _] = sndr; + return @\exposid{query-or-default}@(get_domain, sch, default_domain()); +}(); +\end{codeblock} +\begin{note} +The \tcode{continues_on} algorithm works +in tandem with \tcode{schedule_from}\iref{exec.schedule.from} +to give scheduler authors a way to customize both +how to transition onto (\tcode{continues_on}) and off of (\tcode{schedule_from}) +a given execution context. +Thus, \tcode{continues_on} ignores the domain of the predecessor and +uses the domain of the destination scheduler to select a customization, +a property that is unique to \tcode{continues_on}. +That is why it is given special treatment here. +\end{note} +\item +Otherwise, +\begin{codeblock} +return Domain(); +\end{codeblock} +where \tcode{Domain} is the first of the following expressions +that is well-formed and whose type is not \tcode{void}: +\begin{itemize} +\item \tcode{get_domain(get_env(sndr))} +\item \tcode{\exposid{completion-domain}(sndr)} +\item \tcode{get_domain(env)} +\item \tcode{get_domain(get_scheduler(env))} +\item \tcode{default_domain()} +\end{itemize} +\end{itemize} +\end{itemdescr} + +\pnum +\begin{codeblock} +template<@\exposconcept{callable}@ Fun> + requires is_nothrow_move_constructible_v +struct @\exposid{emplace-from}@ { + Fun @\exposid{fun}@; // \expos + using type = @\exposid{call-result-t}@; + + constexpr operator type() && noexcept(@\exposconcept{nothrow-callable}@) { + return std::move(fun)(); + } + + constexpr type operator()() && noexcept(@\exposconcept{nothrow-callable}@) { + return std::move(fun)(); + } +}; +\end{codeblock} +\begin{note} +\exposid{emplace-from} is used to emplace non-movable types +into \tcode{tuple}, \tcode{optional}, \tcode{variant}, and similar types. +\end{note} + +\pnum +\begin{codeblock} +struct @\exposid{on-stop-request}@ { + inplace_stop_source& @\exposid{stop-src}@; // \expos + void operator()() noexcept { @\exposid{stop-src}@.request_stop(); } +}; +\end{codeblock} + +\pnum +\begin{codeblock} +template +struct @\exposid{product-type}@ { // \expos + T@$_0$@ t@$_0$@; // \expos + T@$_1$@ t@$_1$@; // \expos + @...@ + T@$_n$@ t@$_n$@; // \expos + + template + constexpr decltype(auto) @\exposid{get}@(this Self&& self) noexcept; // \expos + + template + constexpr decltype(auto) @\exposid{apply}@(this Self&& self, Fn&& fn) // \expos + noexcept(@\seebelow@); +}; +\end{codeblock} + +\pnum +\begin{note} +\exposid{product-type} is presented here in pseudo-code form +for the sake of exposition. +It can be approximated in standard \Cpp{} with a tuple-like implementation +that takes care to keep the type an aggregate +that can be used as the initializer of a structured binding declaration. +\end{note} +\begin{note} +An expression of type \exposid{product-type} is usable as +the initializer of a structured binding declaration\iref{dcl.struct.bind}. +\end{note} + +\begin{itemdecl} +template +constexpr decltype(auto) @\exposid{get}@(this Self&& self) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto& [...ts] = self; +return std::forward_like(ts...[I]); +\end{codeblock} +\end{itemdescr} + +\begin{codeblock} +template +constexpr decltype(auto) @\exposid{apply}@(this Self&& self, Fn&& fn) noexcept(@\seebelow@); +\end{codeblock} + +\begin{itemdescr} +\pnum +\constraints +The expression in the \tcode{return} statement below is well-formed. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto& [...ts] = self; +return std::forward(fn)(std::forward_like(ts)...); +\end{codeblock} + +\pnum +\remarks +The expression in the \tcode{noexcept} clause is \tcode{true} +if the \tcode{return} statement above is not potentially throwing; +otherwise, \tcode{false}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr auto @\exposid{make-sender}@(Tag tag, Data&& data, Child&&... child); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The following expressions are \tcode{true}: +\begin{itemize} +\item \tcode{\libconcept{semiregular}} +\item \tcode{\exposconcept{movable-value}} +\item \tcode{(\libconcept{sender} \&\& ...)} +\end{itemize} + +\pnum +\returns +A prvalue of +type \tcode{\exposid{basic-sender}, decay_t...>} +that has been direct-list-initialized with the forwarded arguments, +where \exposid{basic-sender} is the following exposition-only class template except as noted below. +\end{itemdescr} + +\begin{codeblock} +namespace std::execution { + template + concept @\defexposconcept{completion-tag}@ = // \expos + @\libconcept{same_as}@ || @\libconcept{same_as}@ || @\libconcept{same_as}@; + + template class T, class... Args> + concept @\defexposconcept{valid-specialization}@ = // \expos + requires { typename T; }; + + struct @\exposid{default-impls}@ { // \expos + static constexpr auto @\exposid{get-attrs}@ = @\seebelow@; // \expos + static constexpr auto @\exposid{get-env}@ = @\seebelow@; // \expos + static constexpr auto @\exposid{get-state}@ = @\seebelow@; // \expos + static constexpr auto @\exposid{start}@ = @\seebelow@; // \expos + static constexpr auto @\exposid{complete}@ = @\seebelow@; // \expos + }; + + template + struct @\exposid{impls-for}@ : @\exposid{default-impls}@ {}; // \expos + + template // \expos + using @\exposid{state-type}@ = decay_t<@\exposid{call-result-t}@< + decltype(@\exposid{impls-for}@>::@\exposid{get-state}@), Sndr, Rcvr&>>; + + template // \expos + using @\exposid{env-type}@ = @\exposid{call-result-t}@< + decltype(@\exposid{impls-for}@>::@\exposid{get-env}@), Index, + @\exposid{state-type}@&, const Rcvr&>; + + template + using @\exposid{child-type}@ = decltype(declval().template @\exposid{get}@()); // \expos + + template + using @\exposid{indices-for}@ = remove_reference_t::@\exposid{indices-for}@; // \expos + + template + struct @\exposid{basic-state}@ { // \expos + @\exposid{basic-state}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelow@) + : @\exposid{rcvr}@(std::move(rcvr)) + , @\exposid{state}@(@\exposid{impls-for}@>::@\exposid{get-state}@(std::forward(sndr), @\exposid{rcvr}@)) { } + + Rcvr @\exposid{rcvr}@; // \expos + @\exposid{state-type}@ @\exposid{state}@; // \expos + }; + + template + requires @\exposconcept{valid-specialization}@<@\exposid{env-type}@, Index, Sndr, Rcvr> + struct @\exposid{basic-receiver}@ { // \expos + using receiver_concept = receiver_t; + + using @\exposid{tag-t}@ = tag_of_t; // \expos + using @\exposid{state-t}@ = @\exposid{state-type}@; // \expos + static constexpr const auto& @\exposid{complete}@ = @\exposid{impls-for}@<@\exposid{tag-t}@>::@\exposid{complete}@; // \expos + + template + requires @\exposconcept{callable}@ + void set_value(Args&&... args) && noexcept { + @\exposid{complete}@(Index(), op->@\exposid{state}@, op->@\exposid{rcvr}@, set_value_t(), std::forward(args)...); + } + + template + requires @\exposconcept{callable}@ + void set_error(Error&& err) && noexcept { + @\exposid{complete}@(Index(), op->@\exposid{state}@, op->@\exposid{rcvr}@, set_error_t(), std::forward(err)); + } + + void set_stopped() && noexcept + requires @\exposconcept{callable}@ { + @\exposid{complete}@(Index(), op->@\exposid{state}@, op->@\exposid{rcvr}@, set_stopped_t()); + } + + auto get_env() const noexcept -> @\exposid{env-type}@ { + return @\exposid{impls-for}@::@\exposid{get-env}@(Index(), op->@\exposid{state}@, op->@\exposid{rcvr}@); + } + + @\exposid{basic-state}@* @\exposid{op}@; // \expos + }; + + constexpr auto @\exposid{connect-all}@ = @\seebelow@; // \expos + + template + using @\exposid{connect-all-result}@ = @\exposid{call-result-t}@< // \expos + decltype(@\exposid{connect-all}@), @\exposid{basic-state}@*, Sndr, @\exposid{indices-for}@>; + + template + requires @\exposconcept{valid-specialization}@<@\exposid{state-type}@, Sndr, Rcvr> && + @\exposconcept{valid-specialization}@<@\exposid{connect-all-result}@, Sndr, Rcvr> + struct @\exposid{basic-operation}@ : @\exposid{basic-state}@ { // \expos + using operation_state_concept = operation_state_t; + using @\exposid{tag-t}@ = tag_of_t; // \expos + + @\exposid{connect-all-result}@ @\exposid{inner-ops}@; // \expos + + @\exposid{basic-operation}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelow@) // \expos + : @\exposid{basic-state}@(std::forward(sndr), std::move(rcvr)), + @\exposid{inner-ops}@(@\exposid{connect-all}@(this, std::forward(sndr), @\exposid{indices-for}@())) + {} + + void start() & noexcept { + auto& [...ops] = @\exposid{inner-ops}@; + @\exposid{impls-for}@::@\exposid{start}@(this->@\exposid{state}@, this->@\exposid{rcvr}@, ops...); + } + }; + + template + using @\exposid{completion-signatures-for}@ = @\seebelow@; // \expos + + template + struct @\exposid{basic-sender}@ : @\exposid{product-type}@ { // \expos + using sender_concept = sender_t; + using @\exposid{indices-for}@ = index_sequence_for; // \expos + + decltype(auto) get_env() const noexcept { + auto& [_, data, ...child] = *this; + return @\exposid{impls-for}@::@\exposid{get-attrs}@(data, child...); + } + + template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, @\libconcept{receiver}@ Rcvr> + auto connect(this Self&& self, Rcvr rcvr) noexcept(@\seebelow@) + -> @\exposid{basic-operation}@ { + return {std::forward(self), std::move(rcvr)}; + } + + template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, class Env> + auto get_completion_signatures(this Self&& self, Env&& env) noexcept + -> @\exposid{completion-signatures-for}@ { + return {}; + } + }; +} +\end{codeblock} + +\pnum +The default template argument for the \tcode{Data} template parameter +denotes an unspecified empty trivially copyable class type +that models \libconcept{semiregular}. + +\pnum +It is unspecified whether a specialization of \exposid{basic-sender} +is an aggregate. + +\pnum +An expression of type \exposid{basic-sender} is usable as +the initializer of a structured binding declaration\iref{dcl.struct.bind}. + +\pnum +The expression in the \tcode{noexcept} clause of +the constructor of \exposid{basic-state} is +\begin{codeblock} +is_nothrow_move_constructible_v && +@\exposconcept{nothrow-callable}@>::@\exposid{get-state}@), Sndr, Rcvr&> && +(@\libconcept{same_as}@<@\exposid{state-type}@, @\exposid{get-state-result}@> || + is_nothrow_constructible_v<@\exposid{state-type}@, @\exposid{get-state-result}@>) +\end{codeblock} +where \exposid{get-state-result} is +\begin{codeblock} +@\exposid{call-result-t}@>::@\exposid{get-state}@), Sndr, Rcvr&>. +\end{codeblock} + +\pnum +The object \exposid{connect-all} is initialized with +a callable object equivalent to the following lambda: +\begin{itemdecl} +[]( + @\exposid{basic-state}@* op, Sndr&& sndr, index_sequence) noexcept(@\seebelow@) + -> decltype(auto) { + auto& [_, data, ...child] = sndr; + return @\exposid{product-type}@{connect( + std::forward_like(child), + @\exposid{basic-receiver}@>{op})...}; + } +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The expression in the \tcode{return} statement is well-formed. + +\pnum +\remarks +The expression in the \tcode{noexcept} clause is \tcode{true} +if the \tcode{return} statement is not potentially throwing; +otherwise, \tcode{false}. +\end{itemdescr} + +\pnum +The expression in the \tcode{noexcept} clause of +the constructor of \exposid{basic-operation} is: +\begin{codeblock} +is_nothrow_constructible_v<@\exposid{basic-state}@, Self, Rcvr> && +noexcept(@\exposid{connect-all}@(this, std::forward(sndr), @\exposid{indices-for}@())) +\end{codeblock} + +\pnum +The expression in the \tcode{noexcept} clause of +the \tcode{connect} member function of \exposid{basic-sender} is: +\begin{codeblock} +is_nothrow_constructible_v<@\exposid{basic-operation}@, Self, Rcvr> +\end{codeblock} + +\pnum +The member \tcode{\exposid{default-impls}::\exposid{get-attrs}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](const auto&, const auto&... child) noexcept -> decltype(auto) { + if constexpr (sizeof...(child) == 1) + return (@\exposid{FWD-ENV}@(get_env(child)), ...); + else + return env<>(); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{default-impls}::\exposid{get-env}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](auto, auto&, const auto& rcvr) noexcept -> decltype(auto) { + return @\exposid{FWD-ENV}@(get_env(rcvr)); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{default-impls}::\exposid{get-state}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](Sndr&& sndr, Rcvr& rcvr) noexcept -> decltype(auto) { + auto& [_, data, ...child] = sndr; + return std::forward_like(data); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{default-impls}::\exposid{start}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](auto&, auto&, auto&... ops) noexcept -> void { + (execution::start(ops), ...); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{default-impls}::\exposid{complete}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[]( + Index, auto& state, Rcvr& rcvr, Tag, Args&&... args) noexcept + -> void requires @\exposconcept{callable}@ { + static_assert(Index::value == 0); + Tag()(std::move(rcvr), std::forward(args)...); +} +\end{codeblock} + +\pnum +For a subexpression \tcode{sndr} let \tcode{Sndr} be \tcode{decltype((sndr))}. +Let \tcode{rcvr} be a receiver +with an associated environment of type \tcode{Env} +such that \tcode{\libconcept{sender_in}} is \tcode{true}. +\tcode{\exposid{completion-signatures-for}} denotes +a specialization of \tcode{completion_signatures}, +the set of whose template arguments correspond to +the set of completion operations that are potentially evaluated +as a result of starting\iref{exec.async.ops} +the operation state that results from connecting \tcode{sndr} and \tcode{rcvr}. +When \tcode{\libconcept{sender_in}} is \tcode{false}, +the type denoted by \tcode{\exposid{completion-signatures-for}}, +if any, is not a specialization of \tcode{completion_signatures}. + +\recommended +When \tcode{\libconcept{sender_in}} is \tcode{false}, +implementations are encouraged to use the type +denoted by \tcode{\exposid{completion-signatures-for}} +to communicate to users why. + +\begin{itemdecl} +template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> + constexpr auto @\exposid{write-env}@(Sndr&& sndr, Env&& env); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\exposid{write-env} is an exposition-only sender adaptor that, +when connected with a receiver \tcode{rcvr}, +connects the adapted sender with a receiver +whose execution environment is the result of +joining the \exposconcept{queryable} argument \tcode{env} +to the result of \tcode{get_env(rcvr)}. + +\pnum +Let \exposid{write-env-t} be an exposition-only empty class type. + +\pnum +\returns +\begin{codeblock} +@\exposid{make-sender}@(@\exposid{write-env-t}@(), std::forward(env), std::forward(sndr)) +\end{codeblock} + +\pnum +\remarks +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \exposid{write-env-t} as follows: +\begin{codeblock} +template<> +struct @\exposid{impls-for}@<@\exposid{write-env-t}@> : @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-env}@ = + [](auto, const auto& state, const auto& rcvr) noexcept { + return @\seebelow@; + }; +}; +\end{codeblock} +Invocation of +\tcode{\exposid{impls-for}<\exposid{write-env-t}>::\exposid{get-env}} +returns an object \tcode{e} such that +\begin{itemize} +\item +\tcode{decltype(e)} models \exposconcept{queryable} and +\item +given a query object \tcode{q}, +the expression \tcode{e.query(q)} is expression-equivalent +to \tcode{state.query(q)} if that expression is valid, +otherwise, \tcode{e.query(q)} is expression-equivalent +to \tcode{get_env(rcvr).que\-ry(q)}. +\end{itemize} +\end{itemdescr} + +\rSec2[exec.snd.concepts]{Sender concepts} + +\pnum +The \libconcept{sender} concept defines +the requirements for a sender type\iref{exec.async.ops}. +The \libconcept{sender_in} concept defines +the requirements for a sender type +that can create asynchronous operations given an associated environment type. +The \libconcept{sender_to} concept defines +the requirements for a sender type +that can connect with a specific receiver type. +The \tcode{get_env} customization point object is used to access +a sender's associated attributes. +The connect customization point object is used to connect\iref{exec.async.ops} +a sender and a receiver to produce an operation state. + +\begin{codeblock} +namespace std::execution { + template + concept @\exposconcept{valid-completion-signatures}@ = @\seebelow@; // \expos + + template + concept @\defexposconcept{is-sender}@ = // \expos + @\libconcept{derived_from}@; + + template + concept @\defexposconcept{enable-sender}@ = // \expos + @\exposconcept{is-sender}@ || + @\exposconcept{is-awaitable}@>>; // \ref{exec.awaitable} + + template + concept @\deflibconcept{sender}@ = + bool(@\exposconcept{enable-sender}@>) && + requires (const remove_cvref_t& sndr) { + { get_env(sndr) } -> @\exposconcept{queryable}@; + } && + @\libconcept{move_constructible}@> && + @\libconcept{constructible_from}@, Sndr>; + + template> + concept @\deflibconcept{sender_in}@ = + @\libconcept{sender}@ && + @\exposconcept{queryable}@ && + requires (Sndr&& sndr, Env&& env) { + { get_completion_signatures(std::forward(sndr), std::forward(env)) } + -> @\exposconcept{valid-completion-signatures}@; + }; + + template + concept @\deflibconcept{sender_to}@ = + @\libconcept{sender_in}@> && + @\libconcept{receiver_of}@>> && + requires (Sndr&& sndr, Rcvr&& rcvr) { + connect(std::forward(sndr), std::forward(rcvr)); + }; +} +\end{codeblock} + +\pnum +Given a subexpression \tcode{sndr}, +let \tcode{Sndr} be \tcode{decltype((sndr))} and +let \tcode{rcvr} be a receiver +with an associated environment whose type is \tcode{Env}. +A completion operation is a \defnadj{permissible}{completion} +for \tcode{Sndr} and \tcode{Env} +if its completion signature appears in the argument list of the specialization of \tcode{completion_signatures} denoted by +\tcode{completion_signatures_of_t}. +\tcode{Sndr} and \tcode{Env} model \tcode{\libconcept{sender_in}} +if all the completion operations +that are potentially evaluated by connecting \tcode{sndr} to \tcode{rcvr} and +starting the resulting operation state +are permissible completions for \tcode{Sndr} and \tcode{Env}. + +\pnum +A type models +the exposition-only concept \defexposconcept{valid-completion-signatures} +if it denotes a specialization of +the \tcode{completion_signatures} class template. + +\pnum +The exposition-only concepts +\exposconcept{sender-of} and \exposconcept{sender-in-of} +define the requirements for a sender type +that completes with a given unique set of value result types. +\begin{codeblock} +namespace std::execution { + template + using @\exposid{value-signature}@ = set_value_t(As...); // \expos + + template + concept @\defexposconcept{sender-in-of}@ = + @\libconcept{sender_in}@ && + @\exposid{MATCHING-SIG}@( // see \ref{exec.general} + set_value_t(Values...), + value_types_of_t); + + template + concept @\defexposconcept{sender-of}@ = @\exposconcept{sender-in-of}@, Values...>; +} +\end{codeblock} + +\pnum +Let \tcode{sndr} be an expression +such that \tcode{decltype((sndr))} is \tcode{Sndr}. +The type \tcode{tag_of_t} is as follows: +\begin{itemize} +\item +If the declaration +\begin{codeblock} +auto&& [tag, data, ...children] = sndr; +\end{codeblock} +would be well-formed, \tcode{tag_of_t} is +an alias for \tcode{decltype(auto(tag))}. +\item +Otherwise, \tcode{tag_of_t} is ill-formed. +\end{itemize} + +\pnum +Let \exposconcept{sender-for} be an exposition-only concept defined as follows: +\begin{codeblock} +namespace std::execution { + template + concept @\defexposconcept{sender-for}@ = + @\libconcept{sender}@ && + @\libconcept{same_as}@, Tag>; +} +\end{codeblock} + +\pnum +For a type \tcode{T}, +\tcode{\exposid{SET-VALUE-SIG}(T)} denotes the type \tcode{set_value_t()} +if \tcode{T} is \cv{} \tcode{void}; +otherwise, it denotes the type \tcode{set_value_t(T)}. + +\pnum +Library-provided sender types +\begin{itemize} +\item +always expose an overload of a member \tcode{connect} +that accepts an rvalue sender and +\item +only expose an overload of a member \tcode{connect} +that accepts an lvalue sender if they model \libconcept{copy_constructible}. +\end{itemize} + +\rSec2[exec.awaitable]{Awaitable helpers} + +\pnum +The sender concepts recognize awaitables as senders. +For \ref{exec}, an \defn{awaitable} is an expression +that would be well-formed as the operand of a \tcode{co_await} expression +within a given context. + +\pnum +For a subexpression \tcode{c}, +let \tcode{\exposid{GET-AWAITER}(c, p)} be expression-equivalent to +the series of transformations and conversions applied to \tcode{c} +as the operand of an \grammarterm{await-expression} in a coroutine, +resulting in lvalue \tcode{e} as described by \ref{expr.await}, +where \tcode{p} is an lvalue referring to the coroutine's promise, +which has type \tcode{Promise}. +\begin{note} +This includes the invocation of +the promise type's \tcode{await_transform} member if any, +the invocation of the \tcode{operator co_await} +picked by overload resolution if any, and +any necessary implicit conversions and materializations. +\end{note} + +\pnum +Let \exposconcept{is-awaitable} be the following exposition-only concept: +\begin{codeblock} +namespace std { + template + concept @\exposconcept{await-suspend-result}@ = @\seebelow@; // \expos + + template + concept @\defexposconcept{is-awaiter}@ = // \expos + requires (A& a, coroutine_handle h) { + a.await_ready() ? 1 : 0; + { a.await_suspend(h) } -> @\exposconcept{await-suspend-result}@; + a.await_resume(); + }; + + template + concept @\defexposconcept{is-awaitable}@ = // \expos + requires (C (*fc)() noexcept, Promise& p) { + { @\exposid{GET-AWAITER}@(fc(), p) } -> @\exposconcept{is-awaiter}@; + }; +} +\end{codeblock} + +\tcode{\defexposconcept{await-suspend-result}} is \tcode{true} +if and only if one of the following is \tcode{true}: +\begin{itemize} +\item \tcode{T} is \tcode{void}, or +\item \tcode{T} is \tcode{bool}, or +\item \tcode{T} is a specialization of \tcode{coroutine_handle}. +\end{itemize} + +\pnum +For a subexpression \tcode{c} +such that \tcode{decltype((c))} is type \tcode{C}, and +an lvalue \tcode{p} of type \tcode{Promise}, +\tcode{\exposid{await-result-\newline type}} denotes +the type \tcode{decltype(\exposid{GET-AWAITER}(c, p).await_resume())}. + +\pnum +Let \exposid{with-await-transform} be the exposition-only class template: +\begin{codeblock} +namespace std::execution { + template + concept @\defexposconcept{has-as-awaitable}@ = // \expos + requires (T&& t, Promise& p) { + { std::forward(t).as_awaitable(p) } -> @\exposconcept{is-awaitable}@; + }; + + template + struct @\exposid{with-await-transform}@ { // \expos + template + T&& await_transform(T&& value) noexcept { + return std::forward(value); + } + + template<@\exposconcept{has-as-awaitable}@ T> + decltype(auto) await_transform(T&& value) + noexcept(noexcept(std::forward(value).as_awaitable(declval()))) { + return std::forward(value).as_awaitable(static_cast(*this)); + } + }; +} +\end{codeblock} + +\pnum +Let \exposid{env-promise} be the exposition-only class template: +\begin{codeblock} +namespace std::execution { + template + struct @\exposid{env-promise}@ : @\exposid{with-await-transform}@<@\exposid{env-promise}@> { // \expos + @\unspec@ get_return_object() noexcept; + @\unspec@ initial_suspend() noexcept; + @\unspec@ final_suspend() noexcept; + void unhandled_exception() noexcept; + void return_void() noexcept; + coroutine_handle<> unhandled_stopped() noexcept; + + const Env& get_env() const noexcept; + }; +} +\end{codeblock} +\begin{note} +Specializations of \exposid{env-promise} are used only for the purpose of type computation; +its members need not be defined. +\end{note} + +\rSec2[exec.domain.default]{\tcode{execution::default_domain}} + +\pnum +\begin{codeblock} +namespace std::execution { + struct @\libglobal{default_domain}@ { + template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@... Env> + requires (sizeof...(Env) <= 1) + static constexpr @\libconcept{sender}@ decltype(auto) transform_sender(Sndr&& sndr, const Env&... env) + noexcept(@\seebelow@); + + template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> + static constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(Sndr&& sndr, Env&& env) noexcept; + + template + static constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args) + noexcept(@\seebelow@); + }; +} +\end{codeblock} + +\indexlibrarymember{transform_sender}{default_domain}% +\begin{itemdecl} +template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@... Env> + requires (sizeof...(Env) <= 1) +constexpr @\libconcept{sender}@ decltype(auto) transform_sender(Sndr&& sndr, const Env&... env) + noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{e} be the expression +\begin{codeblock} +tag_of_t().transform_sender(std::forward(sndr), env...) +\end{codeblock} +if that expression is well-formed; +otherwise, \tcode{std::forward(sndr)}. + +\pnum +\returns +\tcode{e}. + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept(e)}. +\end{itemdescr} + +\indexlibrarymember{transform_env}{default_domain}% +\begin{itemdecl} +template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> + constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(Sndr&& sndr, Env&& env) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{e} be the expression +\begin{codeblock} +tag_of_t().transform_env(std::forward(sndr), std::forward(env)) +\end{codeblock} +if that expression is well-formed; +otherwise, \tcode{static_cast(std::forward(env))}. + +\pnum +\mandates +\tcode{noexcept(e)} is \tcode{true}. + +\pnum +\returns +\tcode{e}. +\end{itemdescr} + +\indexlibrarymember{apply_sender}{default_domain}% +\begin{itemdecl} +template +constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args) + noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{e} be the expression +\begin{codeblock} + Tag().apply_sender(std::forward(sndr), std::forward(args)...) +\end{codeblock} + +\pnum +\constraints +\tcode{e} is a well-formed expression. + +\pnum +\returns +\tcode{e}. + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept(e)}. +\end{itemdescr} + +\rSec2[exec.snd.transform]{\tcode{execution::transform_sender}} + +\indexlibraryglobal{transform_sender}% +\begin{itemdecl} +namespace std::execution { + template + requires (sizeof...(Env) <= 1) + constexpr @\libconcept{sender}@ decltype(auto) transform_sender(Domain dom, Sndr&& sndr, const Env&... env) + noexcept(@\seebelow@); +} +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \exposid{transformed-sndr} be the expression +\begin{codeblock} +dom.transform_sender(std::forward(sndr), env...) +\end{codeblock} +if that expression is well-formed; otherwise, +\begin{codeblock} +default_domain().transform_sender(std::forward(sndr), env...) +\end{codeblock} +Let \exposid{final-sndr} be the expression \exposid{transformed-sndr} +if \exposid{transformed-sndr} and \exposid{sndr} +have the same type ignoring cv-qualifiers; +otherwise, it is +the expression \tcode{transform_sender(dom, \exposid{transformed-sndr}, env...)}. + +\pnum +\returns +\exposid{final-sndr}. + +\pnum +\remarks +The exception specification is equivalent to +\tcode{noexcept(\exposid{final-sndr})}. +\end{itemdescr} + +\rSec2[exec.snd.transform.env]{\tcode{execution::transform_env}} + +\indexlibraryglobal{transform_env}% +\begin{itemdecl} +namespace std::execution { + template + constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(Domain dom, Sndr&& sndr, Env&& env) noexcept; +} +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{e} be the expression +\begin{codeblock} +dom.transform_env(std::forward(sndr), std::forward(env)) +\end{codeblock} +if that expression is well-formed; otherwise, +\begin{codeblock} +default_domain().transform_env(std::forward(sndr), std::forward(env)) +\end{codeblock} + +\pnum +\mandates +\tcode{noexcept(e)} is \tcode{true}. + +\pnum +\returns +\tcode{e}. +\end{itemdescr} + +\rSec2[exec.snd.apply]{\tcode{execution::apply_sender}} + +\indexlibraryglobal{apply_sender}% +\begin{itemdecl} +namespace std::execution { + template + constexpr decltype(auto) apply_sender(Domain dom, Tag, Sndr&& sndr, Args&&... args) + noexcept(@\seebelow@); +} +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $e$ be the expression +\begin{codeblock} +dom.apply_sender(Tag(), std::forward(sndr), std::forward(args)...) +\end{codeblock} +if that expression is well-formed; otherwise, +\begin{codeblock} +default_domain().apply_sender(Tag(), std::forward(sndr), std::forward(args)...) +\end{codeblock} + +\pnum +\constraints +The expression $e$ is well-formed. + +\pnum +\returns +$e$. + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept($e$)}. +\end{itemdescr} + +\rSec2[exec.getcomplsigs]{\tcode{execution::get_completion_signatures}} + +\pnum +\tcode{get_completion_signatures} is a customization point object. +Let \tcode{sndr} be an expression +such that \tcode{decltype((sndr))} is \tcode{Sndr}, and +let \tcode{env} be an expression +such that \tcode{decltype((env))} is \tcode{Env}. +Let \tcode{new_sndr} be the expression +\tcode{transform_sender(decltype(\exposid{get-domain-late}(sndr, env))\{\}, sndr, env)}, and +let \tcode{NewSndr} be \tcode{decltype((new_sndr))}. +Then \tcode{get_completion_signatures(sndr, env)} is expression-equiva\-lent to +\tcode{(void(sndr), void(env), CS())} +except that \tcode{void(sndr)} and \tcode{void(env)} are +indeterminately sequenced, +where \tcode{CS} is: +\begin{itemize} +\item +\tcode{decltype(new_sndr.get_completion_signatures(env))} +if that type is well-formed, + +\item +Otherwise, \tcode{remove_cvref_t::completion_signatures} +if that type is well-formed, + +\item +Otherwise, +if \tcode{\exposconcept{is-awaitable}>} is \tcode{true}, +then: +\begin{codeblock} +completion_signatures< + @\exposid{SET-VALUE-SIG}@(@\exposid{await-result-type}@>), // \iref{exec.snd.concepts} + set_error_t(exception_ptr), + set_stopped_t()> +\end{codeblock} + +\item +Otherwise, \tcode{CS} is ill-formed. +\end{itemize} + +\pnum +Let \tcode{rcvr} be an rvalue +whose type \tcode{Rcvr} models \libconcept{receiver}, and +let \tcode{Sndr} be the type of a sender +such that \tcode{\libconcept{sender_in}>} is \tcode{true}. +Let \tcode{Sigs...} be the template arguments of +the \tcode{completion_signatures} specialization +named by \tcode{completion_signatures_of_t>}. +Let \tcode{CSO} be a completion function. +If sender \tcode{Sndr} or its operation state cause +the expression \tcode{CSO(rcvr, args...)} +to be potentially evaluated\iref{basic.def.odr} +then there shall be a signature \tcode{Sig} in \tcode{Sigs...} +such that +\begin{codeblock} +@\exposid{MATCHING-SIG}@(@\exposid{decayed-typeof}@(decltype(args)...), Sig) +\end{codeblock} +is \tcode{true}\iref{exec.general}. + +\rSec2[exec.connect]{\tcode{execution::connect}} + +\pnum +\tcode{connect} connects\iref{exec.async.ops} a sender with a receiver. + +\pnum +The name \tcode{connect} denotes a customization point object. +For subexpressions \tcode{sndr} and \tcode{rcvr}, +let \tcode{Sndr} be \tcode{decltype((sndr))} and +\tcode{Rcvr} be \tcode{decltype((rcvr))}, +let \tcode{new_sndr} be the expression +\begin{codeblock} +transform_sender(decltype(@\exposid{get-domain-late}@(sndr, get_env(rcvr))){}, sndr, get_env(rcvr)) +\end{codeblock} +and let \tcode{DS} and \tcode{DR} be +\tcode{decay_t} and \tcode{decay_t}, respectively. + +\pnum +Let \exposid{connect-awaitable-promise} be the following exposition-only class: + +\begin{codeblock} +namespace std::execution { + struct @\exposid{connect-awaitable-promise}@ : @\exposid{with-await-transform}@<@\exposid{connect-awaitable-promise}@> { + + @\exposid{connect-awaitable-promise}@(DS&, DR& rcvr) noexcept : @\exposid{rcvr}@(rcvr) {} + + suspend_always initial_suspend() noexcept { return {}; } + [[noreturn]] suspend_always final_suspend() noexcept { terminate(); } + [[noreturn]] void unhandled_exception() noexcept { terminate(); } + [[noreturn]] void return_void() noexcept { terminate(); } + + coroutine_handle<> unhandled_stopped() noexcept { + set_stopped(std::move(@\exposid{rcvr}@)); + return noop_coroutine(); + } + + @\exposid{operation-state-task}@ get_return_object() noexcept { + return @\exposid{operation-state-task}@{ + coroutine_handle<@\exposid{connect-awaitable-promise}@>::from_promise(*this)}; + } + + env_of_t get_env() const noexcept { + return execution::get_env(@\exposid{rcvr}@); + } + + private: + DR& @\exposid{rcvr}@; // \expos + }; +} +\end{codeblock} + +\pnum +Let \exposid{operation-state-task} be the following exposition-only class: +\begin{codeblock} +namespace std::execution { + struct @\exposid{operation-state-task}@ { // \expos + using operation_state_concept = operation_state_t; + using promise_type = @\exposid{connect-awaitable-promise}@; + + explicit @\exposid{operation-state-task}@(coroutine_handle<> h) noexcept : coro(h) {} + @\exposid{operation-state-task}@(@\exposid{operation-state-task}@&&) = delete; + ~@\exposid{operation-state-task}@() { @\exposid{coro}@.destroy(); } + + void start() & noexcept { + @\exposid{coro}@.resume(); + } + + private: + coroutine_handle<> @\exposid{coro}@; // \expos + }; +} +\end{codeblock} + +\pnum +Let \tcode{V} name the type +\tcode{\exposid{await-result-type}}, +let \tcode{Sigs} name the type +\begin{codeblock} +completion_signatures< + @\exposid{SET-VALUE-SIG}@(V), // see \iref{exec.snd.concepts} + set_error_t(exception_ptr), + set_stopped_t()> +\end{codeblock} +and let \exposid{connect-awaitable} be an exposition-only coroutine +defined as follows: +\begin{codeblock} +namespace std::execution { + template + auto @\exposid{suspend-complete}@(Fun fun, Ts&&... as) noexcept { // \expos + auto fn = [&, fun]() noexcept { fun(std::forward(as)...); }; + + struct awaiter { + decltype(@\exposid{fn}@) @\exposid{fn}@; // \expos + + static constexpr bool await_ready() noexcept { return false; } + void await_suspend(coroutine_handle<>) noexcept { @\exposid{fn}@(); } + [[noreturn]] void await_resume() noexcept { unreachable(); } + }; + return awaiter{@\exposid{fn}@}; + } + + @\exposid{operation-state-task}@ @\exposid{connect-awaitable}@(DS sndr, DR rcvr) requires @\libconcept{receiver_of}@ { + exception_ptr ep; + try { + if constexpr (@\libconcept{same_as}@) { + co_await std::move(sndr); + co_await @\exposid{suspend-complete}@(set_value, std::move(rcvr)); + } else { + co_await @\exposid{suspend-complete}@(set_value, std::move(rcvr), co_await std::move(sndr)); + } + } catch(...) { + ep = current_exception(); + } + co_await @\exposid{suspend-complete}@(set_error, std::move(rcvr), std::move(ep)); + } +} +\end{codeblock} + +\pnum +The expression \tcode{connect(sndr, rcvr)} is expression-equivalent to: +\begin{itemize} +\item +\tcode{new_sndr.connect(rcvr)} if that expression is well-formed. + +\mandates +The type of the expression above satisfies \libconcept{operation_state}. + +\item +Otherwise, \tcode{\exposid{connect-awaitable}(new_sndr, rcvr)}. +\end{itemize} + +\mandates +\tcode{\libconcept{sender} \&\& \libconcept{receiver}} is \tcode{true}. + +\rSec2[exec.factories]{Sender factories} + +\rSec3[exec.schedule]{\tcode{execution::schedule}} + +\pnum +\tcode{schedule} obtains a schedule sender\iref{exec.async.ops} +from a scheduler. + +\pnum +The name \tcode{schedule} denotes a customization point object. +For a subexpression \tcode{sch}, +the expression \tcode{schedule(sch)} is expression-equivalent to +\tcode{sch.schedule()}. + +\pnum +\mandates +The type of \tcode{sch.schedule()} satisfies \libconcept{sender}. + +\pnum +If the expression +\begin{codeblock} +get_completion_scheduler(get_env(sch.schedule())) == sch +\end{codeblock} +is ill-formed or evaluates to \tcode{false}, +the behavior of calling \tcode{schedule(sch)} is undefined. + +\rSec3[exec.just]{\tcode{execution::just}, \tcode{execution::just_error}, \tcode{execution::just_stopped}} + +\pnum +\tcode{just}, \tcode{just_error}, and \tcode{just_stopped} are sender factories +whose asynchronous operations complete synchronously in their start operation +with a value completion operation, +an error completion operation, or +a stopped completion operation, respectively. + +\pnum +The names \tcode{just}, \tcode{just_error}, and \tcode{just_stopped} denote +customization point objects. +Let \exposid{just-cpo} be one of +\tcode{just}, \tcode{just_error}, or \tcode{just_stopped}. +For a pack of subexpressions \tcode{ts}, +let \tcode{Ts} be the pack of types \tcode{decltype((ts))}. +The expression \tcode{\exposid{just-cpo}(ts...)} is ill-formed if +\begin{itemize} +\item +\tcode{(\exposconcept{movable-value} \&\&...)} is \tcode{false}, or +\item +\exposid{just-cpo} is \tcode{just_error} and +\tcode{sizeof...(ts) == 1} is \tcode{false}, or +\item +\exposid{just-cpo} is \tcode{just_stopped} and +\tcode{sizeof...(ts) == 0} is \tcode{false}. +\end{itemize} + +Otherwise, it is expression-equivalent to +\tcode{\exposid{make-sender}(\exposid{just-cpo}, \exposid{product-type}\{ts...\})}. + +For \tcode{just}, \tcode{just_error}, and \tcode{just_stopped}, +let \exposid{set-cpo} be +\tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively. +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \exposid{just-cpo} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<@\exposid{just-cpo}@>> : @\exposid{default-impls}@ { + static constexpr auto @\exposid{start}@ = + [](auto& state, auto& rcvr) noexcept -> void { + auto& [...ts] = state; + @\exposid{set-cpo}@(std::move(rcvr), std::move(ts)...); + }; + }; +} +\end{codeblock} + +\rSec3[exec.read.env]{\tcode{execution::read_env}} + +\pnum +\tcode{read_env} is a sender factory for a sender +whose asynchronous operation completes synchronously in its start operation +with a value completion result equal to +a value read from the receiver's associated environment. + +\pnum +\tcode{read_env} is a customization point object. +For some query object \tcode{q}, +the expression \tcode{read_env(q)} is expression-equivalent to +\tcode{\exposid{make-sender}(read_env, q)}. + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \tcode{read_env} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@> : @\exposid{default-impls}@ { + static constexpr auto start = + [](auto query, auto& rcvr) noexcept -> void { + @\exposid{TRY-SET-VALUE}@(rcvr, query(get_env(rcvr))); + }; + }; +} +\end{codeblock} + +\rSec2[exec.adapt]{Sender adaptors} + +\rSec3[exec.adapt.general]{General} + +\pnum +Subclause \ref{exec.adapt} specifies a set of sender adaptors. + +\pnum +The bitwise inclusive \logop{or} operator is overloaded +for the purpose of creating sender chains. +The adaptors also support function call syntax with equivalent semantics. + +\pnum +Unless otherwise specified: +\begin{itemize} +\item +A sender adaptor is prohibited from causing observable effects, +apart from moving and copying its arguments, +before the returned sender is connected with a receiver using \tcode{connect}, +and \tcode{start} is called on the resulting operation state. +\item +A parent sender\iref{exec.async.ops} with a single child sender \tcode{sndr} has +an associated attribute object equal to +\tcode{\exposid{FWD-ENV}(get_env(sndr))}\iref{exec.fwd.env}. +\item +A parent sender with more than one child sender has +an associated attributes object equal to \tcode{env<>\{\}}. +\item +When a parent sender is connected to a receiver \tcode{rcvr}, +any receiver used to connect a child sender has +an associated environment equal to \tcode{\exposid{FWD-ENV}(get_env(rcvr))}. +\item +These requirements apply to any function +that is selected by the implementation of the sender adaptor. +\end{itemize} + +\pnum +If a sender returned from a sender adaptor specified in \ref{exec.adapt} +is specified to include \tcode{set_error_t(Err)} +among its set of completion signatures +where \tcode{decay_t} denotes the type \tcode{exception_ptr}, +but the implementation does not potentially evaluate +an error completion operation with an \tcode{exception_ptr} argument, +the implementation is allowed to omit +the \tcode{exception_ptr} error completion signature from the set. + +\rSec3[exec.adapt.obj]{Closure objects} + +\pnum +A \defnadj{pipeable}{sender adaptor closure object} is a function object +that accepts one or more \libconcept{sender} arguments and returns a \libconcept{sender}. +For a pipeable sender adaptor closure object \tcode{c} and +an expression \tcode{sndr} +such that \tcode{decltype((sndr))} models \libconcept{sender}, +the following expressions are equivalent and yield a \libconcept{sender}: +\begin{codeblock} +c(sndr) +sndr | c +\end{codeblock} +Given an additional pipeable sender adaptor closure object \tcode{d}, +the expression \tcode{c | d} produces +another pipeable sender adaptor closure object \tcode{e}: + +\tcode{e} is a perfect forwarding call wrapper\iref{func.require} +with the following properties: +\begin{itemize} +\item +Its target object is an object \tcode{d2} of type \tcode{decltype(auto(d))} +direct-non-list-initialized with \tcode{d}. +\item +It has one bound argument entity, +an object \tcode{c2} of type \tcode{decltype(auto(c))} +direct-non-list-initialized with \tcode{c}. +\item +Its call pattern is \tcode{d2(c2(arg))}, +where arg is the argument used in a function call expression of \tcode{e}. +\end{itemize} +The expression \tcode{c | d} is well-formed if and only if +the initializations of the state entities\iref{func.def} of \tcode{e} +are all well-formed. + +\pnum +An object \tcode{t} of type \tcode{T} is +a pipeable sender adaptor closure object +if \tcode{T} models \tcode{\libconcept{derived_from}>}, +\tcode{T} has no other base classes +of type \tcode{sender_adaptor_closure} for any other type \tcode{U}, and +\tcode{T} does not satisfy \libconcept{sender}. + +\pnum +The template parameter \tcode{D} for \tcode{sender_adaptor_closure} can be +an incomplete type. +Before any expression of type \cv{} \tcode{D} appears as +an operand to the \tcode{|} operator, +\tcode{D} shall be complete and +model \tcode{\libconcept{derived_from}>}. +The behavior of an expression involving an object of type \cv{} \tcode{D} +as an operand to the \tcode{|} operator is undefined +if overload resolution selects a program-defined \tcode{operator|} function. + +\pnum +A \defnadj{pipeable}{sender adaptor object} is a customization point object +that accepts a \libconcept{sender} as its first argument and +returns a \libconcept{sender}. +If a pipeable sender adaptor object accepts only one argument, +then it is a pipeable sender adaptor closure object. + +\pnum +If a pipeable sender adaptor object adaptor accepts more than one argument, +then let \tcode{sndr} be an expression +such that \tcode{decltype((sndr))} models \libconcept{sender}, +let \tcode{args...} be arguments +such that \tcode{adaptor(sndr, args...)} is a well-formed expression +as specified below, and +let \tcode{BoundArgs} be a pack that denotes \tcode{decltype(auto(args))...}. +The expression \tcode{adaptor(args...)} produces +a pipeable sender adaptor closure object \tcode{f} +that is a perfect forwarding call wrapper with the following properties: +\begin{itemize} +\item +Its target object is a copy of adaptor. +\item +Its bound argument entities \tcode{bound_args} consist of +objects of types \tcode{BoundArgs...} direct-non-list-initialized with +\tcode{std::forward(args)...}, respectively. +\item +Its call pattern is \tcode{adaptor(rcvr, bound_args...)}, +where \tcode{rcvr} is +the argument used in a function call expression of \tcode{f}. +\end{itemize} +The expression \tcode{adaptor(args...)} is well-formed if and only if +the initializations of the bound argument entities of the result, +as specified above, are all well-formed. + +\rSec3[exec.starts.on]{\tcode{execution::starts_on}} + +\pnum +\tcode{starts_on} adapts an input sender into a sender +that will start on an execution agent belonging to +a particular scheduler's associated execution resource. + +\pnum +The name \tcode{starts_on} denotes a customization point object. +For subexpressions \tcode{sch} and \tcode{sndr}, +if \tcode{decltype((\newline sch))} does not satisfy \libconcept{scheduler}, or +\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, +\tcode{starts_on(sch, sndr)} is ill-formed. + +\pnum +Otherwise, +the expression \tcode{starts_on(sch, sndr)} is expression-equivalent to: +\begin{codeblock} +transform_sender( + @\exposid{query-or-default}@(get_domain, sch, default_domain()), + @\exposid{make-sender}@(starts_on, sch, sndr)) +\end{codeblock} +except that \tcode{sch} is evaluated only once. + +\pnum +Let \tcode{out_sndr} and \tcode{env} be subexpressions +such that \tcode{OutSndr} is \tcode{decltype((out_sndr))}. +If \tcode{\exposconcept{sender-for}} is \tcode{false}, +then the expressions \tcode{starts_on.transform_env(out_sndr, env)} and\linebreak +\tcode{starts_on.transform_sender(out_sndr, env)} are ill-formed; otherwise +\begin{itemize} +\item +\tcode{starts_on.transform_env(out_sndr, env)} is equivalent to: +\begin{codeblock} +auto&& [_, sch, _] = out_sndr; +return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ENV}@(sch), @\exposid{FWD-ENV}@(env)); +\end{codeblock} +\item +\tcode{starts_on.transform_sender(out_sndr, env)} is equivalent to: +\begin{codeblock} +auto&& [_, sch, sndr] = out_sndr; +return let_value( + schedule(sch), + [sndr = std::forward_like(sndr)]() mutable + noexcept(is_nothrow_move_constructible_v>) { + return std::move(sndr); + }); +\end{codeblock} +\end{itemize} + +\pnum +Let \tcode{out_sndr} be a subexpression denoting +a sender returned from \tcode{starts_on(sch, sndr)} or one equal to such, and +let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. +Let \tcode{out_rcvr} be a subexpression denoting a receiver +that has an environment of type \tcode{Env} +such that \tcode{\libconcept{sender_in}} is \tcode{true}. +Let \tcode{op} be an lvalue referring to the operation state +that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}. +Calling \tcode{start(op)} shall start \tcode{sndr} +on an execution agent of the associated execution resource of \tcode{sch}. +If scheduling onto \tcode{sch} fails, +an error completion on \tcode{out_rcvr} shall be executed +on an unspecified execution agent. + +\rSec3[exec.continues.on]{\tcode{execution::continues_on}} + +\pnum +\tcode{continues_on} adapts a sender into one +that completes on the specified scheduler. + +\pnum +The name \tcode{continues_on} denotes a pipeable sender adaptor object. +For subexpressions \tcode{sch} and \tcode{sndr}, +if \tcode{decltype((sch))} does not satisfy \libconcept{scheduler}, or +\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, +\tcode{continues_on(sndr, sch)} is ill-formed. + +\pnum +Otherwise, +the expression \tcode{continues_on(sndr, sch)} is expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(continues_on, sch, sndr)) +\end{codeblock} +except that \tcode{sndr} is evaluated only once. + +\pnum +The exposition-only class template \exposid{impls-for} +is specialized for \tcode{continues_on_t} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-attrs}@ = + [](const auto& data, const auto& child) noexcept -> decltype(auto) { + return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ATTRS}@(data), @\exposid{FWD-ENV}@(get_env(child))); + }; + }; +} +\end{codeblock} + +\pnum +Let \tcode{sndr} and \tcode{env} be subexpressions +such that \tcode{Sndr} is \tcode{decltype((sndr))}. +If \tcode{\exposconcept{sender-for}} is \tcode{false}, +then +the expression \tcode{continues_on.transform_sender(sndr, env)} is ill-formed; +otherwise, it is equal to: +\begin{codeblock} +auto [_, data, child] = sndr; +return schedule_from(std::move(data), std::move(child)); +\end{codeblock} +\begin{note} +This causes the \tcode{continues_on(sndr, sch)} sender to become +\tcode{schedule_from(sch, sndr)} when it is connected with a receiver +whose execution domain does not customize \tcode{continues_on}. +\end{note} + +\pnum +Let \tcode{out_sndr} be a subexpression denoting +a sender returned from \tcode{continues_on(sndr, sch)} or one equal to such, and +let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. +Let \tcode{out_rcvr} be a subexpression denoting a receiver +that has an environment of type \tcode{Env} +such that \tcode{\libconcept{sender_in}} is \tcode{true}. +Let \tcode{op} be an lvalue referring to the operation state +that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}. +Calling \tcode{start(op)} shall +start \tcode{sndr} on the current execution agent and +execute completion operations on \tcode{out_rcvr} +on an execution agent of the execution resource associated with \tcode{sch}. +If scheduling onto \tcode{sch} fails, +an error completion on \tcode{out_rcvr} shall be executed +on an unspecified execution agent. + +\rSec3[exec.schedule.from]{\tcode{execution::schedule_from}} + +\pnum +\tcode{schedule_from} schedules work dependent on the completion of a sender +onto a scheduler's associated execution resource. +\begin{note} +\tcode{schedule_from} is not meant to be used in user code; +it is used in the implementation of \tcode{continues_on}. +\end{note} + +\pnum +The name \tcode{schedule_from} denotes a customization point object. +For some subexpressions \tcode{sch} and \tcode{sndr}, +let \tcode{Sch} be \tcode{decltype((sch))} and +\tcode{Sndr} be \tcode{decltype((sndr))}. +If \tcode{Sch} does not satisfy \libconcept{scheduler}, or +\tcode{Sndr} does not satisfy \libconcept{sender}, +\tcode{schedule_from(sch, sndr)} is ill-formed. + +\pnum +Otherwise, +the expression \tcode{schedule_from(sch, sndr)} is expression-equivalent to: +\begin{codeblock} +transform_sender( + @\exposid{query-or-default}@(get_domain, sch, default_domain()), + @\exposid{make-sender}@(schedule_from, sch, sndr)) +\end{codeblock} +except that \tcode{sch} is evaluated only once. + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \tcode{schedule_from_t} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-attrs}@ = @\seebelow@; + static constexpr auto @\exposid{get-state}@ = @\seebelow@; + static constexpr auto @\exposid{complete}@ = @\seebelow@; + }; +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-attrs}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](const auto& data, const auto& child) noexcept -> decltype(auto) { + return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ATTRS}@(data), @\exposid{FWD-ENV}@(get_env(child))); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-state}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](Sndr&& sndr, Rcvr& rcvr) noexcept(@\seebelow@) + requires @\libconcept{sender_in}@<@\exposid{child-type}@, env_of_t> { + + auto& [_, sch, child] = sndr; + + using sched_t = decltype(auto(sch)); + using variant_t = @\seebelow@; + using receiver_t = @\seebelow@; + using operation_t = connect_result_t, receiver_t>; + constexpr bool nothrow = noexcept(connect(schedule(sch), receiver_t{nullptr})); + + struct @\exposid{state-type}@ { + Rcvr& @\exposid{rcvr}@; // \expos + variant_t @\exposid{async-result}@; // \expos + operation_t @\exposid{op-state}@; // \expos + + explicit @\exposid{state-type}@(sched_t sch, Rcvr& rcvr) noexcept(nothrow) + : @\exposid{rcvr}@(rcvr), @\exposid{op-state}@(connect(schedule(sch), receiver_t{this})) {} + }; + + return @\exposid{state-type}@{sch, rcvr}; +} +\end{codeblock} + +\pnum +Objects of the local class \exposid{state-type} can be used +to initialize a structured binding. + +\pnum +Let \tcode{Sigs} be +a pack of the arguments to the \tcode{completion_signatures} specialization +named by \tcode{completion_signatures_of_t<\exposid{child-type}, env_of_t>}. +Let \exposid{as-tuple} be an alias template +that transforms a completion signature \tcode{Tag(Args...)} into +the tuple specialization \tcode{\exposid{decayed-tuple}}. +Then \tcode{variant_t} denotes +the type \tcode{variant...>}, +except with duplicate types removed. + +\pnum +\tcode{receiver_t} is an alias for the following exposition-only class: +\begin{codeblock} +namespace std::execution { + struct @\exposid{receiver-type}@ { + using receiver_concept = receiver_t; + @\exposid{state-type}@* @\exposid{state}@; // \expos + + void set_value() && noexcept { + visit( + [this](Tuple& result) noexcept -> void { + if constexpr (!@\libconcept{same_as}@) { + auto& [tag, ...args] = result; + tag(std::move(@\exposid{state}@->@\exposid{rcvr}@), std::move(args)...); + } + }, + @\exposid{state}@->@\exposid{async-result}@); + } + + template + void set_error(Error&& err) && noexcept { + execution::set_error(std::move(@\exposid{state}@->@\exposid{rcvr}@), std::forward(err)); + } + + void set_stopped() && noexcept { + execution::set_stopped(std::move(@\exposid{state}@->@\exposid{rcvr}@)); + } + + decltype(auto) get_env() const noexcept { + return @\exposid{FWD-ENV}@(execution::get_env(@\exposid{state}@->@\exposid{rcvr}@)); + } + }; +} +\end{codeblock} + +\pnum +The expression in the \tcode{noexcept} clause of the lambda is \tcode{true} +if the construction of the returned \exposid{state-type} object +is not potentially throwing; +otherwise, \tcode{false}. + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{complete}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept + -> void { + using result_t = @\exposid{decayed-tuple}@; + constexpr bool nothrow = is_nothrow_constructible_v; + + try { + state.@\exposid{async-result}@.template emplace(Tag(), std::forward(args)...); + } catch (...) { + if constexpr (!nothrow) { + set_error(std::move(rcvr), current_exception()); + return; + } + } + start(state.@\exposid{op-state}@); +}; +\end{codeblock} + +\pnum +Let \tcode{out_sndr} be a subexpression denoting +a sender returned from \tcode{schedule_from(sch, sndr)} or one equal to such, +and let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. +Let \tcode{out_rcvr} be a subexpression denoting a receiver +that has an environment of type \tcode{Env} +such that \tcode{\libconcept{sender_in}} is \tcode{true}. +Let \tcode{op} be an lvalue referring to the operation state +that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}. +Calling \tcode{start(op)} shall +start \tcode{sndr} on the current execution agent and +execute completion operations on \tcode{out_rcvr} +on an execution agent of the execution resource associated with \tcode{sch}. +If scheduling onto \tcode{sch} fails, +an error completion on \tcode{out_rcvr} shall be executed +on an unspecified execution agent. + +\rSec3[exec.on]{\tcode{execution::on}} + +\pnum +The \tcode{on} sender adaptor has two forms: +\begin{itemize} +\item +\tcode{on(sch, sndr)}, +which starts a sender \tcode{sndr} on an execution agent +belonging to a scheduler \tcode{sch}'s associated execution resource and +that, upon \tcode{sndr}'s completion, +transfers execution back to the execution resource +on which the \tcode{on} sender was started. +\item +\tcode{on(sndr, sch, closure)}, +which upon completion of a sender \tcode{sndr}, +transfers execution to an execution agent +belonging to a scheduler \tcode{sch}'s associated execution resource, +then executes a sender adaptor closure \tcode{closure} +with the async results of the sender, and +that then transfers execution back to the execution resource +on which \tcode{sndr} completed. +\end{itemize} + +\pnum +The name \tcode{on} denotes a pipeable sender adaptor object. +For subexpressions \tcode{sch} and \tcode{sndr}, +\tcode{on(sch, sndr)} is ill-formed if any of the following is \tcode{true}: +\begin{itemize} +\item +\tcode{decltype((sch))} does not satisfy \libconcept{scheduler}, or +\item +\tcode{decltype((sndr))} does not satisfy \libconcept{sender} and +\tcode{sndr} is not +a pipeable sender adaptor closure object\iref{exec.adapt.obj}, or +\item +\tcode{decltype((sndr))} satisfies \libconcept{sender} and +\tcode{sndr }is also a pipeable sender adaptor closure object. +\end{itemize} + +\pnum +Otherwise, if \tcode{decltype((sndr))} satisfies \libconcept{sender}, +the expression \tcode{on(sch, sndr)} is expression-equivalent to: +\begin{codeblock} +transform_sender( + @\exposid{query-or-default}@(get_domain, sch, default_domain()), + @\exposid{make-sender}@(on, sch, sndr)) +\end{codeblock} +except that \tcode{sch} is evaluated only once. + +\pnum +For subexpressions \tcode{sndr}, \tcode{sch}, and \tcode{closure}, if +\begin{itemize} +\item +\tcode{decltype((sch))} does not satisfy \libconcept{scheduler}, or +\item +\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or +\item +\tcode{closure} is not a pipeable sender adaptor closure object\iref{exec.adapt.obj}, +\end{itemize} +the expression \tcode{on(sndr, sch, closure)} is ill-formed; +otherwise, it is expression-equivalent to: +\begin{codeblock} +transform_sender( + @\exposid{get-domain-early}@(sndr), + @\exposid{make-sender}@(on, @\exposid{product-type}@{sch, closure}, sndr)) +\end{codeblock} +except that \tcode{sndr} is evaluated only once. + +\pnum +Let \tcode{out_sndr} and \tcode{env} be subexpressions, +let \tcode{OutSndr} be \tcode{decltype((out_sndr))}, and +let \tcode{Env} be \tcode{decltype((\linebreak env))}. +If \tcode{\exposconcept{sender-for}} is \tcode{false}, +then the expressions \tcode{on.transform_env(out_sndr, env)} and +\tcode{on.transform_sender(out_sndr, env)} are ill-formed. + +\pnum +Otherwise: +Let \exposid{not-a-scheduler} be an unspecified empty class type, and +let \exposid{not-a-sender} be the exposition-only type: +\begin{codeblock} +struct @\exposid{not-a-sender}@ { + using sender_concept = sender_t; + + auto get_completion_signatures(auto&&) const { + return @\seebelow@; + } +}; +\end{codeblock} +where the member function \tcode{get_completion_signatures} returns +an object of a type that is not +a specialization of the \tcode{completion_signatures} class template. + +\pnum +The expression \tcode{on.transform_env(out_sndr, env)} +has effects equivalent to: +\begin{codeblock} +auto&& [_, data, _] = out_sndr; +if constexpr (@\libconcept{scheduler}@) { + return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ENV}@(std::forward_like(data)), @\exposid{FWD-ENV}@(std::forward(env))); +} else { + return std::forward(env); +} +\end{codeblock} + +\pnum +The expression \tcode{on.transform_sender(out_sndr, env)} +has effects equivalent to: +\begin{codeblock} +auto&& [_, data, child] = out_sndr; +if constexpr (@\libconcept{scheduler}@) { + auto orig_sch = + @\exposid{query-with-default}@(get_scheduler, env, @\exposid{not-a-scheduler}@()); + + if constexpr (@\libconcept{same_as}@) { + return @\exposid{not-a-sender}@{}; + } else { + return continues_on( + starts_on(std::forward_like(data), std::forward_like(child)), + std::move(orig_sch)); + } +} else { + auto& [sch, closure] = data; + auto orig_sch = @\exposid{query-with-default}@( + get_completion_scheduler, + get_env(child), + @\exposid{query-with-default}@(get_scheduler, env, @\exposid{not-a-scheduler}@())); + + if constexpr (@\libconcept{same_as}@) { + return @\exposid{not-a-sender}@{}; + } else { + return @\exposid{write-env}@( + continues_on( + std::forward_like(closure)( + continues_on( + @\exposid{write-env}@(std::forward_like(child), @\exposid{SCHED-ENV}@(orig_sch)), + sch)), + orig_sch), + @\exposid{SCHED-ENV}@(sch)); + } +} +\end{codeblock} + +\pnum +\recommended +Implementations should use +the return type of \tcode{\exposid{not-a-sender}::get_completion_signatures} +to inform users that their usage of \tcode{on} is incorrect +because there is no available scheduler onto which to restore execution. + +\pnum +Let \tcode{out_sndr} be a subexpression denoting +a sender returned from \tcode{on(sch, sndr)} or one equal to such, and +let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. +Let \tcode{out_rcvr} be a subexpression denoting a receiver +that has an environment of type \tcode{Env} +such that \tcode{\libconcept{sender_in}} is \tcode{true}. +Let \tcode{op} be an lvalue referring to the operation state +that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}. +Calling \tcode{start(op)} shall +\begin{itemize} +\item +remember the current scheduler, \tcode{get_scheduler(get_env(rcvr))}; +\item +start \tcode{sndr} on an execution agent belonging to +sch's associated execution resource; +\item +upon \tcode{sndr}'s completion, +transfer execution back to the execution resource +associated with the scheduler remembered in step 1; and +\item +forward \tcode{sndr}'s async result to \tcode{out_rcvr}. +\end{itemize} +If any scheduling operation fails, +an error completion on \tcode{out_rcvr} shall be executed +on an unspecified execution agent. + +\pnum +Let \tcode{out_sndr} be a subexpression denoting +a sender returned from \tcode{on(sndr, sch, closure)} or one equal to such, and +let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. +Let \tcode{out_rcvr} be a subexpression denoting a receiver +that has an environment of type \tcode{Env} +such that \tcode{\libconcept{sender_in}} is \tcode{true}. +Let \tcode{op} be an lvalue referring to the operation state +that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}. +Calling \tcode{start(op)} shall +\begin{itemize} +\item +remember the current scheduler, +which is the first of the following expressions that is well-formed: +\begin{itemize} +\item \tcode{get_completion_scheduler(get_env(sndr))} +\item \tcode{get_scheduler(get_env(rcvr))}; +\end{itemize} +\item +start \tcode{sndr} on the current execution agent; +\item +upon \tcode{sndr}'s completion, +transfer execution to an agent +owned by sch's associated execution resource; +\item +forward \tcode{sndr}'s async result as if by +connecting and starting a sender \tcode{closure(S)}, +where \tcode{S} is a sender +that completes synchronously with \tcode{sndr}'s async result; and +\item +upon completion of the operation started in the previous step, +transfer execution back to the execution resource +associated with the scheduler remembered in step 1 and +forward the operation's async result to \tcode{out_rcvr}. +\end{itemize} +If any scheduling operation fails, +an error completion on \tcode{out_rcvr} shall be executed on +an unspecified execution agent. + +\rSec3[exec.then]{\tcode{execution::then}, \tcode{execution::upon_error}, \tcode{execution::upon_stopped}} + +\pnum +\tcode{then} attaches an invocable as a continuation +for an input sender's value completion operation. +\tcode{upon_error} and \tcode{upon_stopped} do the same +for the error and stopped completion operations, respectively, +sending the result of the invocable as a value completion. + +\pnum +The names \tcode{then}, \tcode{upon_error}, and \tcode{upon_stopped} +denote pipeable sender adaptor objects. +Let the expression \exposid{then-cpo} be one of +\tcode{then}, \tcode{upon_error}, or \tcode{upon_stopped}. +For subexpressions \tcode{sndr} and \tcode{f}, +if \tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or +\tcode{decltype((f))} does not satisfy \exposconcept{movable-value}, +\tcode{\exposid{then-cpo}(\linebreak sndr, f) }is ill-formed. + +\pnum +Otherwise, +the expression \tcode{\exposid{then-cpo}(sndr, f)} is expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(@\exposid{then-cpo}@, f, sndr)) +\end{codeblock} +except that \tcode{sndr} is evaluated only once. + +\pnum +For \tcode{then}, \tcode{upon_error}, and \tcode{upon_stopped}, +let \exposid{set-cpo} be +\tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively. +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \exposid{then-cpo} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<@\exposid{then-cpo}@>> : @\exposid{default-impls}@ { + static constexpr auto @\exposid{complete}@ = + [] + (auto, auto& fn, auto& rcvr, Tag, Args&&... args) noexcept -> void { + if constexpr (@\libconcept{same_as}@>) { + @\exposid{TRY-SET-VALUE}@(rcvr, + invoke(std::move(fn), std::forward(args)...)); + } else { + Tag()(std::move(rcvr), std::forward(args)...); + } + }; + }; +} +\end{codeblock} + +\pnum +The expression \tcode{\exposid{then-cpo}(sndr, f)} has undefined behavior +unless it returns a sender \tcode{out_sndr} that +\begin{itemize} +\item +invokes \tcode{f} or a copy of such +with the value, error, or stopped result datums of \tcode{sndr} +for \tcode{then}, \tcode{upon_error}, and \tcode{upon_stopped}, respectively, +using the result value of \tcode{f} as \tcode{out_sndr}'s value completion, and +\item +forwards all other completion operations unchanged. +\end{itemize} + +\rSec3[exec.let]{\tcode{execution::let_value}, \tcode{execution::let_error}, \tcode{execution::let_stopped}} + +\pnum +\tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped} transform +a sender's value, error, and stopped completions, respectively, +into a new child asynchronous operation +by passing the sender's result datums to a user-specified callable, +which returns a new sender that is connected and started. + +\pnum +For \tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped}, +let \exposid{set-cpo} be +\tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively. +Let the expression \exposid{let-cpo} be one of +\tcode{let_value}, \tcode{let_error}, or \tcode{let_stopped}. +For a subexpression \tcode{sndr}, +let \tcode{\exposid{let-env}(sndr)} be expression-equivalent to +the first well-formed expression below: +\begin{itemize} +\item +\tcode{\exposid{SCHED-ENV}(get_completion_scheduler<\exposid{decayed-typeof}<\exposid{set-cpo}>>(get_env(sndr)))} +\item +\tcode{\exposid{MAKE-ENV}(get_domain, get_domain(get_env(sndr)))} +\item +\tcode{(void(sndr), env<>\{\})} +\end{itemize} + +\pnum +The names \tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped} denote +pipeable sender adaptor objects. +For subexpressions \tcode{sndr} and \tcode{f}, +let \tcode{F} be the decayed type of \tcode{f}. +If \tcode{decltype((sndr))} does not satisfy \libconcept{sender} or +if \tcode{decltype((f))} does not satisfy \exposconcept{movable-value}, +the expression \tcode{\exposid{let-cpo}(sndr, f)} is ill-formed. +If \tcode{F} does not satisfy \libconcept{invocable}, +the expression \tcode{let_stopped(sndr, f)} is ill-formed. + +\pnum +Otherwise, +the expression \tcode{\exposid{let-cpo}(sndr, f)} is expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(@\exposid{let-cpo}@, f, sndr)) +\end{codeblock} +except that \tcode{sndr} is evaluated only once. + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \exposid{let-cpo} as follows: +\begin{codeblock} +namespace std::execution { + template + void @\exposid{let-bind}@(State& state, Rcvr& rcvr, Args&&... args); // \expos + + template<> + struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<@\exposid{let-cpo}@>> : @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-state}@ = @\seebelow@; + static constexpr auto @\exposid{complete}@ = @\seebelow@; + }; +} +\end{codeblock} + +\pnum +Let \exposid{receiver2} denote the following exposition-only class template: +\begin{codeblock} +namespace std::execution { + template + struct @\exposid{receiver2}@ { + using receiver_concept = receiver_t; + + template + void set_value(Args&&... args) && noexcept { + execution::set_value(std::move(@\exposid{rcvr}@), std::forward(args)...); + } + + template + void set_error(Error&& err) && noexcept { + execution::set_error(std::move(@\exposid{rcvr}@), std::forward(err)); + } + + void set_stopped() && noexcept { + execution::set_stopped(std::move(@\exposid{rcvr}@)); + } + + decltype(auto) get_env() const noexcept { + return @\seebelow@; + } + + Rcvr& @\exposid{rcvr}@; // \expos + Env @\exposid{env}@; // \expos + }; +} +\end{codeblock} +Invocation of the function \tcode{\exposid{receiver2}::get_env} +returns an object \tcode{e} such that +\begin{itemize} +\item +\tcode{decltype(e)} models \exposconcept{queryable} and +\item +given a query object \tcode{q}, +the expression \tcode{e.query(q)} is expression-equivalent +to \tcode{\exposid{env}.query(q)} if that expression is valid, +otherwise \tcode{e.query(q)} is expression-equivalent +to \tcode{get_env(\exposid{rcvr}).query(q)}. +\end{itemize} + +\pnum +\tcode{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>::\exposid{get-state}} +is initialized with a callable object equivalent to the following: +\begin{codeblock} +[](Sndr&& sndr, Rcvr& rcvr) requires @\seebelow@ { + auto& [_, fn, child] = sndr; + using fn_t = decay_t; + using env_t = decltype(@\exposid{let-env}@(child)); + using args_variant_t = @\seebelow@; + using ops2_variant_t = @\seebelow@; + + struct @\exposid{state-type}@ { + fn_t @\exposid{fn}@; // \expos + env_t @\exposid{env}@; // \expos + args_variant_t @\exposid{args}@; // \expos + ops2_variant_t @\exposid{ops2}@; // \expos + }; + return @\exposid{state-type}@{std::forward_like(fn), @\exposid{let-env}@(child), {}, {}}; +} +\end{codeblock} + +\pnum +Let \tcode{Sigs} be a pack of the arguments +to the \tcode{completion_signatures} specialization named by +\tcode{completion_signatures_of_t<\exposid{child-type}, env_of_t>}. +Let \tcode{LetSigs} be a pack of those types in \tcode{Sigs} +with a return type of \tcode{\exposid{decayed-typeof}<\exposid{set-cpo}>}. +Let \exposid{as-tuple} be an alias template +such that \tcode{\exposid{as-tuple}<\linebreak Tag(Args...)>} denotes +the type \tcode{\exposid{decayed-tuple}}. +Then \tcode{args_variant_t} denotes +the type \tcode{variant...>} +except with duplicate types removed. + +\pnum +Given a type \tcode{Tag} and a pack \tcode{Args}, +let \exposid{as-sndr2} be an alias template +such that \tcode{\exposid{as-sndr2}} denotes +the type \tcode{\exposid{call-result-t}\&...>}. +Then \tcode{ops2_variant_t} denotes +the type +\begin{codeblock} +variant, @\exposid{receiver2}@>...> +\end{codeblock} +except with duplicate types removed. + +\pnum +The \grammarterm{requires-clause} constraining the above lambda is satisfied +if and only if +the types \tcode{args_variant_t} and \tcode{ops2_variant_t} are well-formed. + +\pnum +The exposition-only function template \exposid{let-bind} +has effects equivalent to: +\begin{codeblock} +using args_t = @\exposid{decayed-tuple}@; +auto mkop2 = [&] { + return connect( + apply(std::move(state.fn), + state.args.template emplace(std::forward(args)...)), + @\exposid{receiver2}@{rcvr, std::move(state.env)}); +}; +start(state.ops2.template emplace(@\exposid{emplace-from}@{mkop2})); +\end{codeblock} + +\pnum +\tcode{\exposid{impls-for}<\exposid{decayed-typeof}>::\exposid{complete}} +is initialized with a callable object equivalent to the following: +\begin{codeblock} +[] + (auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void { + if constexpr (@\libconcept{same_as}@>) { + @\exposid{TRY-EVAL}@(rcvr, @\exposid{let-bind}@(state, rcvr, std::forward(args)...)); + } else { + Tag()(std::move(rcvr), std::forward(args)...); + } + } +\end{codeblock} + +\pnum +Let \tcode{sndr} and \tcode{env} be subexpressions, and +let \tcode{Sndr} be \tcode{decltype((sndr))}. +If +\tcode{\exposconcept{sender-for}>} +is \tcode{false}, +then the expression \tcode{\exposid{let-cpo}.transform_env(sndr, env)} +is ill-formed. +Otherwise, it is equal to +\tcode{\exposid{JOIN-ENV}(\exposid{let-env}(sndr), \exposid{FWD-ENV}(env))}. + +\pnum +Let the subexpression \tcode{out_sndr} denote +the result of the invocation \tcode{\exposid{let-cpo}(sndr, f)} or +an object equal to such, and +let the subexpression \tcode{rcvr} denote a receiver +such that the expression \tcode{connect(out_sndr, rcvr)} is well-formed. +The expression \tcode{connect(out_sndr, rcvr)} has undefined behavior +unless it creates an asynchronous operation\iref{exec.async.ops} that, +when started: +\begin{itemize} +\item +invokes \tcode{f} when \exposid{set-cpo} is called +with \tcode{sndr}'s result datums, +\item +makes its completion dependent on +the completion of a sender returned by \tcode{f}, and +\item +propagates the other completion operations sent by \tcode{sndr}. +\end{itemize} + +\rSec3[exec.bulk]{\tcode{execution::bulk}} + +\pnum +\tcode{bulk} runs a task repeatedly for every index in an index space. + +The name \tcode{bulk} denotes a pipeable sender adaptor object. +For subexpressions \tcode{sndr}, \tcode{shape}, and \tcode{f}, +let \tcode{Shape} be \tcode{decltype(auto(shape))}. +If +\begin{itemize} +\item +\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, or +\item +\tcode{Shape} does not satisfy \libconcept{integral}, or +\item +\tcode{decltype((f))} does not satisfy \exposconcept{movable-value}, +\end{itemize} +\tcode{bulk(sndr, shape, f)} is ill-formed. + +\pnum +Otherwise, +the expression \tcode{bulk(sndr, shape, f)} is expression-equivalent to: + +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(bulk, @\exposid{product-type}@{shape, f}, sndr)) +\end{codeblock} +except that \tcode{sndr} is evaluated only once. + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \tcode{bulk_t} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { + static constexpr auto @\exposid{complete}@ = @\seebelow@; + }; +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{complete}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[] + (Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept -> void requires @\seebelow@ { + if constexpr (@\libconcept{same_as}@) { + auto& [shape, f] = state; + constexpr bool nothrow = noexcept(f(auto(shape), args...)); + @\exposid{TRY-EVAL}@(rcvr, [&]() noexcept(nothrow) { + for (decltype(auto(shape)) i = 0; i < shape; ++i) { + f(auto(i), args...); + } + Tag()(std::move(rcvr), std::forward(args)...); + }()); + } else { + Tag()(std::move(rcvr), std::forward(args)...); + } + } +\end{codeblock} + +\pnum +The expression in the \grammarterm{requires-clause} of the lambda above +is \tcode{true} if and only +if \tcode{Tag} denotes a type other than \tcode{set_value_t} or +if the expression \tcode{f(auto(shape), args...)} is well-formed. + +\pnum +Let the subexpression \tcode{out_sndr} denote +the result of the invocation \tcode{bulk(sndr, shape, f)} or +an object equal to such, and +let the subexpression \tcode{rcvr} denote a receiver +such that the expression \tcode{connect(out_sndr, rcvr)} is well-formed. +The expression \tcode{connect(out_sndr, rcvr)} has undefined behavior +unless it creates an asynchronous operation\iref{exec.async.ops} that, +when started, +\begin{itemize} +\item +on a value completion operation, +invokes \tcode{f(i, args...)} +for every \tcode{i} of type \tcode{Shape} in \range{\tcode{0}}{\tcode{shape}}, +where \tcode{args} is a pack of lvalue subexpressions +referring to the value completion result datums of the input sender, and +\item +propagates all completion operations sent by \tcode{sndr}. +\end{itemize} + +\rSec3[exec.split]{\tcode{execution::split}} + +\pnum +\tcode{split} adapts an arbitrary sender +into a sender that can be connected multiple times. + +\pnum +Let \exposid{split-env} be the type of an environment +such that, given an instance \tcode{env}, +the expression \tcode{get_stop_token(env)} is well-formed and +has type \tcode{inplace_stop_token.} + +\pnum +The name \tcode{split} denotes a pipeable sender adaptor object. +For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. +If \tcode{\libconcept{sender_in}} is \tcode{false}, +\tcode{split(sndr)} is ill-formed. + +\pnum +Otherwise, the expression \tcode{split(sndr)} is expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(split, {}, sndr)) +\end{codeblock} +except that \tcode{sndr} is evaluated only once. +\begin{note} +The default implementation of \tcode{transform_sender} +will have the effect of connecting the sender to a receiver. +It will return a sender with a different tag type. +\end{note} + +\pnum +Let \exposid{local-state} denote the following exposition-only class template: + +\begin{codeblock} +namespace std::execution { + struct @\exposid{local-state-base}@ { // \expos + virtual ~@\exposid{local-state-base}@() = default; + virtual void @\exposid{notify}@() noexcept = 0; // \expos + }; + + template + struct @\exposid{local-state}@ : @\exposid{local-state-base}@ { // \expos + using @\exposid{on-stop-callback}@ = // \expos + stop_callback_for_t>, @\exposid{on-stop-request}@>; + + @\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; + ~@\exposid{local-state}@(); + + void @\exposid{notify}@() noexcept override; + + private: + optional<@\exposid{on-stop-callback}@> @\exposid{on_stop}@; // \expos + @\exposid{shared-state}@* @\exposid{sh_state}@; // \expos + Rcvr* @\exposid{rcvr}@; // \expos + }; +} +\end{codeblock} + +\begin{itemdecl} +@\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto& [_, data, _] = sndr; +this->@\exposid{sh_state}@ = data.sh_state.get(); +this->@\exposid{sh_state}@->@\exposid{inc-ref}@(); +this->@\exposid{rcvr}@ = addressof(rcvr); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +~@\exposid{local-state}@(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +sh_state->@\exposid{dec-ref}@(); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +void @\exposid{notify}@() noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{on_stop}@.reset(); +visit( + [this](const auto& tupl) noexcept -> void { + apply( + [this](auto tag, const auto&... args) noexcept -> void { + tag(std::move(*@\exposid{rcvr}@), args...); + }, + tupl); + }, + @\exposid{sh_state}@->result); +\end{codeblock} +\end{itemdescr} + +\pnum +Let \exposid{split-receiver} denote +the following exposition-only class template: +\begin{codeblock} +namespace std::execution { + template + struct @\exposid{split-receiver}@ { // \expos + using receiver_concept = receiver_t; + + template + void @\exposid{complete}@(Tag, Args&&... args) noexcept { // \expos + using tuple_t = @\exposid{decayed-tuple}@; + try { + @\exposid{sh_state}@->result.template emplace(Tag(), std::forward(args)...); + } catch (...) { + using tuple_t = tuple; + @\exposid{sh_state}@->result.template emplace(set_error, current_exception()); + } + @\exposid{sh_state}@->notify(); + } + + template + void set_value(Args&&... args) && noexcept { + @\exposid{complete}@(execution::set_value, std::forward(args)...); + } + + template + void set_error(Error&& err) && noexcept { + @\exposid{complete}@(execution::set_error, std::forward(err)); + } + + void set_stopped() && noexcept { + @\exposid{complete}@(execution::set_stopped); + } + + struct @\exposid{env}@ { // \expos + @\exposid{shared-state}@* @\exposid{sh-state}@; // \expos + + inplace_stop_token query(get_stop_token_t) const noexcept { + return @\exposid{sh-state}@->stop_src.get_token(); + } + }; + + @\exposid{env}@ get_env() const noexcept { + return @\exposid{env}@{@\exposid{sh_state}@}; + } + + @\exposid{shared-state}@* @\exposid{sh_state}@; // \expos + }; +} +\end{codeblock} + +\pnum +Let \exposid{shared-state} denote the following exposition-only class template: +\begin{codeblock} +namespace std::execution { + template + struct @\exposid{shared-state}@ { + using @\exposid{variant-type}@ = @\seebelow@; // \expos + using @\exposid{state-list-type}@ = @\seebelow@; // \expos + + explicit @\exposid{shared-state}@(Sndr&& sndr); + + void @\exposid{start-op}@() noexcept; // \expos + void @\exposid{notify}@() noexcept; // \expos + void @\exposid{inc-ref}@() noexcept; // \expos + void @\exposid{dec-ref}@() noexcept; // \expos + + inplace_stop_source @\exposid{stop_src}@{}; // \expos + @\exposid{variant-type}@ @\exposid{result}@{}; // \expos + @\exposid{state-list-type}@ @\exposid{waiting_states}@; // \expos + atomic @\exposid{completed}@{false}; // \expos + atomic @\exposid{ref_count}@{1}; // \expos + connect_result_t> @\exposid{op_state}@; // \expos + }; +} +\end{codeblock} + +\pnum +Let \tcode{Sigs} be a pack of the arguments +to the \tcode{completion_signatures} specialization +named by \tcode{completion_signatures_of_t}. +For type \tcode{Tag} and pack \tcode{Args}, +let \exposid{as-tuple} be an alias template +such that \tcode{\exposid{as-tuple}} denotes +the type \tcode{\exposid{decayed-tuple}}. +Then \exposid{variant-type} denotes the type +\begin{codeblock} +variant, tuple, @\exposid{as-tuple}@...> +\end{codeblock} +but with duplicate types removed. + +\pnum +Let \exposid{state-list-type} be a type +that stores a list of pointers to \exposid{local-state-base} objects and +that permits atomic insertion. + +\begin{itemdecl} +explicit @\exposid{shared-state}@(Sndr&& sndr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{op_state} with the result of +\tcode{connect(std::forward(sndr), \exposid{split-re\-ceiver}\{this\})}. + +\pnum +\ensures +\exposid{waiting_states} is empty, and \exposid{completed} is \tcode{false}. +\end{itemdescr} + +\begin{itemdecl} +void @\exposid{start-op}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Evaluates \tcode{\exposid{inc-ref}()}. +If \tcode{stop_src.stop_requested()} is \tcode{true}, +evaluates \tcode{\exposid{notify}()}; +otherwise, evaluates \tcode{start(\exposid{op_state})}. +\end{itemdescr} + +\begin{itemdecl} +void @\exposid{notify}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Atomically does the following: +\begin{itemize} +\item +Sets \tcode{completed} to \tcode{true}, and +\item +Exchanges \tcode{waiting_states} with an empty list, +storing the old value in a local \tcode{prior_states}. +\end{itemize} +Then, for each pointer \tcode{p} in \tcode{prior_states}, +evaluates \tcode{p->\exposid{notify}()}. +Finally, evaluates \tcode{\exposid{dec-ref}()}. +\end{itemdescr} + +\begin{itemdecl} +void @\exposid{inc-ref}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Increments \exposid{ref_count}. +\end{itemdescr} + +\begin{itemdecl} +void @\exposid{dec-ref}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Decrements \exposid{ref_count}. +If the new value of \exposid{ref_count} is \tcode{0}, +calls \tcode{delete this}. + +\pnum +\sync +If an evaluation of \tcode{\exposid{dec-ref}()} does not +decrement the \tcode{ref_count} to \tcode{0} then +synchronizes with the evaluation of \tcode{dec-ref()} +that decrements \tcode{ref_count} to \tcode{0}. +\end{itemdescr} + +\pnum +Let \exposid{split-impl-tag} be an empty exposition-only class type. +Given an expression \tcode{sndr}, +the expression \tcode{split.transform_sender(sndr)} is equivalent to: +\begin{codeblock} +auto&& [tag, _, child] = sndr; +auto* sh_state = new @\exposid{shared-state}@{std::forward_like(child)}; +return @\exposid{make-sender}@(@\exposid{split-impl-tag}@(), @\exposid{shared-wrapper}@{sh_state, tag}); +\end{codeblock} +where \exposid{shared-wrapper} is an exposition-only class +that manages the reference count of the \exposid{shared-state} object +pointed to by sh_state. +\exposid{shared-wrapper} models \libconcept{copyable} +with move operations nulling out the moved-from object, +copy operations incrementing the reference count +by calling \tcode{sh_state->\exposid{inc-ref}()}, and +assignment operations performing a copy-and-swap operation. +The destructor has no effect if sh_state is null; +otherwise, it decrements the reference count +by evaluating \tcode{sh_state->\exposid{dec-ref}()}. + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \exposid{split-impl-tag} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@<@\exposid{split-impl-tag}@> : @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-state}@ = @\seebelow@; + static constexpr auto @\exposid{start}@ = @\seebelow@; + }; +} +\end{codeblock} + +\pnum +The member +\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{get-state}} +is initialized with a callable object equivalent to +the following lambda expression: +\begin{codeblock} +[](Sndr&& sndr, auto& rcvr) noexcept { + return @\exposid{local-state}@{std::forward(sndr), rcvr}; +} +\end{codeblock} + +\pnum +The member +\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{start}} +is initialized with a callable object +that has a function call operator equivalent to the following: +\begin{codeblock} +template +void operator()(@\exposid{local-state}@& state, Rcvr& rcvr) const noexcept; +\end{codeblock} + +\effects +If \tcode{state.\exposid{sh_state}->\exposid{completed}} is \tcode{true}, +evaluates \tcode{state.\exposid{notify}()} and returns. +Otherwise, does the following in order: +\begin{itemize} +\item +Evaluates +\begin{codeblock} +state.@\exposid{on_stop}@.emplace( + get_stop_token(get_env(rcvr)), + @\exposid{on-stop-request}@{state.@\exposid{sh_state}@->@\exposid{stop_src}@}); +\end{codeblock} +\item +Then atomically does the following: +\begin{itemize} +\item +Reads the value \tcode{c} of +\tcode{state.\exposid{sh_state}->\exposid{completed}}, and +\item +Inserts \tcode{addressof(state)} into +\tcode{state.\exposid{sh_state}->\exposid{waiting_states}} +if \tcode{c} is \tcode{false}. +\end{itemize} +\item +If \tcode{c} is \tcode{true}, +calls \tcode{state.\exposid{notify}()} and returns. +\item +Otherwise, +if \tcode{addressof(state)} is the first item added to +\tcode{state.\exposid{sh_state}->\exposid{waiting_states}}, +evaluates \tcode{state.\exposid{sh_state}->\exposid{start-op}()}. +\end{itemize} + +\rSec3[exec.when.all]{\tcode{execution::when_all}} + +\pnum +\tcode{when_all} and \tcode{when_all_with_variant} +both adapt multiple input senders into a sender +that completes when all input senders have completed. +\tcode{when_all} only accepts senders +with a single value completion signature and +on success concatenates all the input senders' value result datums +into its own value completion operation. +\tcode{when_all_with_variant(sndrs...)} is semantically equivalent to +w\tcode{hen_all(into_variant(sndrs)...)}, +where \tcode{sndrs} is a pack of subexpressions +whose types model \libconcept{sender}. + +\pnum +The names \tcode{when_all} and \tcode{when_all_with_variant} denote +customization point objects. +Let \tcode{sndrs} be a pack of subexpressions, +let \tcode{Sndrs} be a pack of the types \tcode{decltype((sndrs))...}, and +let \tcode{CD} be +the type \tcode{common_type_t}. +The expressions \tcode{when_all(sndrs...)} and +\tcode{when_all_with_variant(sndrs...)} are ill-formed +if any of the following is \tcode{true}: +\begin{itemize} +\item +\tcode{sizeof...(sndrs)} is \tcode{0}, or +\item +\tcode{(\libconcept{sender} \&\& ...)} is \tcode{false}, or +\item +\tcode{CD} is ill-formed. +\end{itemize} + +\pnum +The expression \tcode{when_all(sndrs...)} is expression-equivalent to: +\begin{codeblock} +transform_sender(CD(), @\exposid{make-sender}@(when_all, {}, sndrs...)) +\end{codeblock} + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \tcode{when_all_t} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-attrs}@ = @\seebelow@; + static constexpr auto @\exposid{get-env}@ = @\seebelow@; + static constexpr auto @\exposid{get-state}@ = @\seebelow@; + static constexpr auto @\exposid{start}@ = @\seebelow@; + static constexpr auto @\exposid{complete}@ = @\seebelow@; + }; +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-attrs}} +is initialized with a callable object +equivalent to the following lambda expression: +\begin{codeblock} +[](auto&&, auto&&... child) noexcept { + if constexpr (@\libconcept{same_as}@) { + return env<>(); + } else { + return @\exposid{MAKE-ENV}@(get_domain, CD()); + } +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-env}} +is initialized with a callable object +equivalent to the following lambda expression: +\begin{codeblock} +[](auto&&, State& state, const Receiver& rcvr) noexcept { + return @\seebelow@; +} +\end{codeblock} +Returns an object \tcode{e} such that +\begin{itemize} +\item +\tcode{decltype(e)} models \exposconcept{queryable}, and +\item +\tcode{e.query(get_stop_token)} is expression-equivalent to +\tcode{state.\exposid{stop-src}.get_token()}, and +\item +given a query object \tcode{q} with type other than \cv{} \tcode{stop_token_t}, +\tcode{e.query(q)} is expression-equivalent to \tcode{get_env(rcvr).query(q)}. +\end{itemize} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-state}} +is initialized with a callable object +equivalent to the following lambda expression: +\begin{codeblock} +[](Sndr&& sndr, Rcvr& rcvr) noexcept(@$e$@) -> decltype(@$e$@) { + return @$e$@; +} +\end{codeblock} +where $e$ is the expression +\begin{codeblock} +std::forward(sndr).apply(@\exposid{make-state}@()) +\end{codeblock} +and where \exposid{make-state} is the following exposition-only class template: +\begin{codeblock} +template +concept @\defexposconcept{max-1-sender-in}@ = @\libconcept{sender_in}@ && // \expos + (tuple_size_v> <= 1); + +enum class @\exposid{disposition}@ { @\exposid{started}@, @\exposid{error}@, @\exposid{stopped}@ }; // \expos + +template +struct @\exposid{make-state}@ { + template<@\exposconcept{max-1-sender-in}@>... Sndrs> + auto operator()(auto, auto, Sndrs&&... sndrs) const { + using values_tuple = @\seebelow@; + using errors_variant = @\seebelow@; + using stop_callback = stop_callback_for_t>, @\exposid{on-stop-request}@>; + + struct @\exposid{state-type}@ { + void @\exposid{arrive}@(Rcvr& rcvr) noexcept { // \expos + if (0 == --count) { + @\exposid{complete}@(rcvr); + } + } + + void @\exposid{complete}@(Rcvr& rcvr) noexcept; // \expos + + atomic @\exposid{count}@{sizeof...(sndrs)}; // \expos + inplace_stop_source @\exposid{stop_src}@{}; // \expos + atomic<@\exposid{disposition}@> disp{@\exposidnc{disposition}@::@\exposidnc{started}@}; // \expos + errors_variant @\exposid{errors}@{}; // \expos + values_tuple @\exposid{values}@{}; // \expos + optional @\exposid{on_stop}@{nullopt}; // \expos + }; + + return @\exposid{state-type}@{}; + } +}; +\end{codeblock} + +\pnum +Let \exposid{copy-fail} be \tcode{exception_ptr} +if decay-copying any of the child senders' result datums can potentially throw; +otherwise, \exposid{none-such}, +where \exposid{none-such} is an unspecified empty class type. + +\pnum +The alias \tcode{values_tuple} denotes the type +\begin{codeblock} +tuple, @\exposid{decayed-tuple}@, optional>...> +\end{codeblock} +if that type is well-formed; otherwise, \tcode{tuple<>}. + +\pnum +The alias \tcode{errors_variant} denotes +the type \tcode{variant<\exposid{none-such}, \exposid{copy-fail}, Es...>} +with duplicate types removed, +where \tcode{Es} is the pack of the decayed types +of all the child senders' possible error result datums. + +\pnum +The member +\tcode{void \exposid{state-type}::\exposid{complete}(Rcvr\& rcvr) noexcept} +behaves as follows: +\begin{itemize} +\item +If \tcode{disp} is equal to \tcode{\exposid{disposition}::\exposid{started}}, +evaluates: +\begin{codeblock} +auto tie = [](tuple& t) noexcept { return tuple(t); }; +auto set = [&](auto&... t) noexcept { set_value(std::move(rcvr), std::move(t)...); }; + +@\exposid{on_stop}@.reset(); +apply( + [&](auto&... opts) noexcept { + apply(set, tuple_cat(tie(*opts)...)); + }, + values); +\end{codeblock} +\item +Otherwise, +if \tcode{disp} is equal to \tcode{\exposid{disposition}::\exposid{error}}, +evaluates: +\begin{codeblock} +@\exposid{on_stop}@.reset(); +visit( + [&](Error& error) noexcept { + if constexpr (!@\libconcept{same_as}@) { + set_error(std::move(rcvr), std::move(error)); + } + }, + errors); +\end{codeblock} +\item +Otherwise, evaluates: +\begin{codeblock} +@\exposid{on_stop}@.reset(); +set_stopped(std::move(rcvr)); +\end{codeblock} +\end{itemize} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{start}} +is initialized with a callable object +equivalent to the following lambda expression: +\begin{codeblock} +[]( + State& state, Rcvr& rcvr, Ops&... ops) noexcept -> void { + state.@\exposid{on_stop}@.emplace( + get_stop_token(get_env(rcvr)), + @\exposid{on-stop-request}@{state.@\exposid{stop_src}@}); + if (state.@\exposid{stop_src}@.stop_requested()) { + state.@\exposid{on_stop.}@reset(); + set_stopped(std::move(rcvr)); + } else { + (start(ops), ...); + } +} +\end{codeblock} + +\pnum +The member \exposid{\tcode{impls-for}::\exposid{complete}} +is initialized with a callable object +equivalent to the following lambda expression: +\begin{codeblock} +[]( + this auto& complete, Index, State& state, Rcvr& rcvr, Set, Args&&... args) noexcept -> void { + if constexpr (@\libconcept{same_as}@) { + if (@\exposid{disposition}@::@\exposid{error}@ != state.disp.exchange(@\exposid{disposition}@::@\exposid{error}@)) { + state.@\exposid{stop_src}@.request_stop(); + @\exposid{TRY-EMPLACE-ERROR}@(state.errors, std::forward(args)...); + } + } else if constexpr (@\libconcept{same_as}@) { + auto expected = @\exposid{disposition}@::@\exposid{started}@; + if (state.disp.compare_exchange_strong(expected, @\exposid{disposition}@::@\exposid{stopped}@)) { + state.@\exposid{stop_src}@.request_stop(); + } + } else if constexpr (!@\libconcept{same_as}@>) { + if (state.disp == @\exposid{disposition}@::@\exposid{started}@) { + auto& opt = get(state.values); + @\exposid{TRY-EMPLACE-VALUE}@(complete, opt, std::forward(args)...); + } + } + state.@\exposid{arrive}@(rcvr); +} +\end{codeblock} +where \tcode{\exposid{TRY-EMPLACE-ERROR}(v, e)}, +for subexpressions \tcode{v} and \tcode{e}, is equivalent to: +\begin{codeblock} +try { + v.template emplace(e); +} catch (...) { + v.template emplace(current_exception()); +} +\end{codeblock} +if the expression \tcode{decltype(auto(e))(e)} is potentially throwing; +otherwise, \tcode{v.template emplace(e)}; +and where \tcode{\exposid{TRY-EMPLACE-VALUE}(c, o, as...)}, +for subexpressions \tcode{c}, \tcode{o}, and pack of subexpressions \tcode{as}, +is equivalent to: +\begin{codeblock} +try { + o.emplace(as...); +} catch (...) { + c(Index(), state, rcvr, set_error, current_exception()); + return; +} +\end{codeblock} +if the expression \tcode{\exposid{decayed-tuple}\{as...\}} +is potentially throwing; +otherwise, \tcode{o.emplace(\linebreak as...)}. + +\pnum +The expression \tcode{when_all_with_variant(sndrs...)} +is expression-equivalent to: +\begin{codeblock} +transform_sender(CD(), @\exposid{make-sender}@(when_all_with_variant, {}, sndrs...)); +\end{codeblock} + +\pnum +Given subexpressions \tcode{sndr} and \tcode{env}, +if +\tcode{\exposconcept{sender-for}} +is \tcode{false}, +then the expression \tcode{when_all_with_variant.transform_sender(sndr, env)} +is ill-formed; +otherwise, it is equivalent to: +\begin{codeblock} +auto&& [_, _, ...child] = sndr; +return when_all(into_variant(std::forward_like(child))...); +\end{codeblock} +\begin{note} +This causes the \tcode{when_all_with_variant(sndrs...)} sender +to become \tcode{when_all(into_variant(sndrs)...)} +when it is connected with a receiver +whose execution domain does not customize \tcode{when_all_with_variant}. +\end{note} + +\rSec3[exec.into.variant]{\tcode{execution::into_variant}} + +\pnum +\tcode{into_variant} adapts a sender with multiple value completion signatures +into a sender with just one value completion signature +consisting of a \tcode{variant} of \tcode{tuple}s. + +\pnum +The name \tcode{into_variant} denotes a pipeable sender adaptor object. +For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. +If \tcode{Sndr} does not satisfy \libconcept{sender}, +\tcode{into_variant(sndr)} is ill-formed. + +\pnum +Otherwise, the expression \tcode{into_variant(sndr)} +is expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(into_variant, {}, sndr)) +\end{codeblock} +except that \tcode{sndr} is only evaluated once. + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \tcode{into_variant} as follows: +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-state}@ = @\seebelow@; + static constexpr auto @\exposid{complete}@ = @\seebelow@; + }; +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-state}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](Sndr&& sndr, Rcvr& rcvr) noexcept + -> type_identity, env_of_t>> { + return {}; +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{complete}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[]( + auto, State, Rcvr& rcvr, Tag, Args&&... args) noexcept -> void { + if constexpr (@\libconcept{same_as}@) { + using variant_type = typename State::type; + @\exposid{TRY-SET-VALUE}@(rcvr, variant_type(@\exposid{decayed-tuple}@{std::forward(args)...})); + } else { + Tag()(std::move(rcvr), std::forward(args)...); + } +} +\end{codeblock} + +\rSec3[exec.stopped.opt]{\tcode{execution::stopped_as_optional}} + +\pnum +\tcode{stopped_as_optional} maps a sender's stopped completion operation +into a value completion operation as a disengaged \tcode{optional}. +The sender's value completion operation +is also converted into an \tcode{optional}. +The result is a sender that never completes with stopped, +reporting cancellation by completing with a disengaged \tcode{optional}. + +\pnum +The name \tcode{stopped_as_optional} denotes a pipeable sender adaptor object. +For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. +The expression \tcode{stopped_as_optional(sndr)} is expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(stopped_as_optional, {}, sndr)) +\end{codeblock} +except that \tcode{sndr} is only evaluated once. + +\pnum +Let \tcode{sndr} and \tcode{env} be subexpressions +such that \tcode{Sndr} is \tcode{decltype((sndr))} and +\tcode{Env} is \tcode{decltype((env))}. +If \tcode{\exposconcept{sender-for}} +is \tcode{false}, or +if the type \tcode{\exposid{single-sender-value-type}} +is ill-formed or \tcode{void}, +then the expression \tcode{stopped_as_optional.transform_sender(sndr, env)} +is ill-formed; +otherwise, it is equivalent to: +\begin{codeblock} +auto&& [_, _, child] = sndr; +using V = @\exposid{single-sender-value-type}@; +return let_stopped( + then(std::forward_like(child), + [](Ts&&... ts) noexcept(is_nothrow_constructible_v) { + return optional(in_place, std::forward(ts)...); + }), + []() noexcept { return just(optional()); }); +\end{codeblock} + +\rSec3[exec.stopped.err]{\tcode{execution::stopped_as_error}} + +\pnum +\tcode{stopped_as_error} maps an input sender's stopped completion operation +into an error completion operation as a custom error type. +The result is a sender that never completes with stopped, +reporting cancellation by completing with an error. + +\pnum +The name \tcode{stopped_as_error} denotes a pipeable sender adaptor object. +For some subexpressions \tcode{sndr} and \tcode{err}, +let \tcode{Sndr} be \tcode{decltype((sndr))} and +let \tcode{Err} be \tcode{decltype((err))}. +If the type \tcode{Sndr} does not satisfy \libconcept{sender} or +if the type \tcode{Err} does not satisfy \exposconcept{movable-value}, +\tcode{stopped_as_error(sndr, err)} is ill-formed. +Otherwise, the expression \tcode{stopped_as_error(sndr, err)} +is expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(stopped_as_error, err, sndr)) +\end{codeblock} +except that \tcode{sndr} is only evaluated once. + +\pnum +Let \tcode{sndr} and \tcode{env} be subexpressions +such that \tcode{Sndr} is \tcode{decltype((sndr))} and +\tcode{Env} is \tcode{decltype((env))}. +If \tcode{\exposconcept{sender-for}} is \tcode{false}, +then the expression \tcode{stopped_as_error.transform_sender(sndr, env)} +is ill-formed; +otherwise, it is equivalent to: +\begin{codeblock} +auto&& [_, err, child] = sndr; +using E = decltype(auto(err)); +return let_stopped( + std::forward_like(child), + [err = std::forward_like(err)]() mutable noexcept(is_nothrow_move_constructible_v) { + return just_error(std::move(err)); + }); +\end{codeblock} + +\rSec2[exec.consumers]{Sender consumers} + +\rSec3[exec.sync.wait]{\tcode{this_thread::sync_wait}} + +\pnum +\tcode{this_thread::sync_wait} and \tcode{this_thread::sync_wait_with_variant} +are used +to block the current thread of execution +until the specified sender completes and +to return its async result. +\tcode{sync_wait} mandates +that the input sender has exactly one value completion signature. + +\pnum +Let \exposid{sync-wait-env} be the following exposition-only class type: +\begin{codeblock} +namespace std::this_thread { + struct @\exposid{sync-wait-env}@ { + execution::run_loop* @\exposid{loop}@; // \expos + + auto query(execution::get_scheduler_t) const noexcept { + return @\exposid{loop}@->get_scheduler(); + } + + auto query(execution::get_delegation_scheduler_t) const noexcept { + return @\exposid{loop}@->get_scheduler(); + } + }; +} +\end{codeblock} + +\pnum +Let \exposid{sync-wait-result-type} and +\exposid{sync-wait-with-variant-result-type} +be exposition-only alias templates defined as follows: +\begin{codeblock} +namespace std::this_thread { + template Sndr> + using @\exposid{sync-wait-result-type}@ = + optional>; + + template Sndr> + using @\exposid{sync-wait-with-variant-result-type}@ = + optional>; +} +\end{codeblock} + +\pnum +The name \tcode{this_thread::sync_wait} denotes a customization point object. +For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. +If \tcode{\libconcept{sender_in}} +is \tcode{false}, +the expression \tcode{this_thread::sync_wait(sndr)} is ill-formed. +Otherwise, it is expression-equivalent to the following, +except that \tcode{sndr} is evaluated only once: +\begin{codeblock} +apply_sender(@\exposid{get-domain-early}@(sndr), sync_wait, sndr) +\end{codeblock} +\mandates +\begin{itemize} +\item +The type \tcode{\exposid{sync-wait-result-type}} is well-formed. +\item +\tcode{\libconcept{same_as}>} +is \tcode{true}, where $e$ is the \tcode{apply_sender} expression above. +\end{itemize} + +\pnum +Let \exposid{sync-wait-state} and \exposid{sync-wait-receiver} +be the following exposition-only class templates: +\begin{codeblock} +namespace std::this_thread { + template + struct @\exposid{sync-wait-state}@ { // \expos + execution::run_loop @\exposid{loop}@; // \expos + exception_ptr @\exposid{error}@; // \expos + @\exposid{sync-wait-result-type}@ @\exposidnc{result}@; // \expos + }; + + template + struct @\exposid{sync-wait-receiver}@ { // \expos + using receiver_concept = execution::receiver_t; + @\exposidnc{sync-wait-state}@* @\exposid{state}@; // \expos + + template + void set_value(Args&&... args) && noexcept; + + template + void set_error(Error&& err) && noexcept; + + void set_stopped() && noexcept; + + @\exposid{sync-wait-env}@ get_env() const noexcept { return {&@\exposid{state}@->@\exposid{loop}@}; } + }; +} +\end{codeblock} + +\begin{itemdecl} +template +void set_value(Args&&... args) && noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +try { + @\exposid{state}@->@\exposid{result}@.emplace(std::forward(args)...); +} catch (...) { + @\exposid{state}@->@\exposid{error}@ = current_exception(); +} +@\exposid{state}@->@\exposid{loop}@.finish(); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +template +void set_error(Error&& err) && noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{state}@->@\exposid{error}@ = @\exposid{AS-EXCEPT-PTR}@(std::forward(err)); // see \ref{exec.general} +@\exposid{state}@->@\exposid{loop}@.finish(); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +void set_stopped() && noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{\exposid{state}->\exposid{loop}.finish()}. +\end{itemdescr} + +\pnum +For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. +If \tcode{\libconcept{sender_to}>} +is \tcode{false}, +the expression \tcode{sync_wait.apply_sender(sndr)} is ill-formed; +otherwise, it is equivalent to: +\begin{codeblock} +@\exposid{sync-wait-state}@ state; +auto op = connect(sndr, @\exposid{sync-wait-receiver}@{&state}); +start(op); + +state.@\exposid{loop}@.run(); +if (state.@\exposid{error}@) { + rethrow_exception(std::move(state.@\exposid{error}@)); +} +return std::move(state.@\exposid{result}@); +\end{codeblock} + +\pnum +The behavior of \tcode{this_thread::sync_wait(sndr)} is undefined unless: +\begin{itemize} +\item +It blocks the current thread of execution\iref{defns.block} +with forward progress guarantee delegation\iref{intro.progress} +until the specified sender completes. +\begin{note} +The default implementation of \tcode{sync_wait} achieves +forward progress guarantee delegation by providing a \tcode{run_loop} scheduler +via the \tcode{get_delegation_scheduler} query +on the \exposid{sync-wait-receiver}'s environment. +The \tcode{run_loop} is driven by the current thread of execution. +\end{note} +\item +It returns the specified sender's async results as follows: +\begin{itemize} +\item +For a value completion, +the result datums are returned in +a \tcode{tuple} in an engaged \tcode{optional} object. +\item +For an error completion, an exception is thrown. +\item +For a stopped completion, a disengaged \tcode{optional} object is returned. +\end{itemize} +\end{itemize} + +\rSec3[exec.sync.wait.var]{\tcode{this_thread::sync_wait_with_variant}} + +\pnum +The name \tcode{this_thread::sync_wait_with_variant} denotes +a customization point object. +For a subexpression \tcode{sndr}, +let \tcode{Sndr} be \tcode{decltype(into_variant(sndr))}. +If \tcode{\libconcept{sender_in}} +is \tcode{false}, +\tcode{this_thread::sync_wait_with_variant(sndr)} is ill-formed. +Otherwise, it is expression-equivalent to the following, +except \tcode{sndr} is evaluated only once: +\begin{codeblock} +apply_sender(@\exposid{get-domain-early}@(sndr), sync_wait_with_variant, sndr) +\end{codeblock} +\mandates +\begin{itemize} +\item +The type \tcode{\exposid{sync-wait-with-variant-result-type}} +is well-formed. +\item +\tcode{\libconcept{same_as}>} +is \tcode{true}, where $e$ is the \tcode{ap\-ply_sender} expression above. +\end{itemize} + +\pnum +If \tcode{\exposconcept{callable}} is \tcode{false}, +the expression \tcode{sync_wait_with_variant.apply_sender(\linebreak sndr)} is ill-formed. +Otherwise, it is equivalent to: +\begin{codeblock} +using result_type = @\exposid{sync-wait-with-variant-result-type}@; +if (auto opt_value = sync_wait(into_variant(sndr))) { + return result_type(std::move(get<0>(*opt_value))); +} +return result_type(nullopt); +\end{codeblock} + +\pnum +The behavior of \tcode{this_thread::sync_wait_with_variant(sndr)} +is undefined unless: +\begin{itemize} +\item +It blocks the current thread of execution\iref{defns.block} +with forward progress guarantee delegation\iref{intro.progress} +until the specified sender completes. +\begin{note} +The default implementation of \tcode{sync_wait_with_variant} achieves +forward progress guarantee delegation by relying on +the forward progress guarantee delegation provided by \tcode{sync_wait}. +\end{note} +\item +It returns the specified sender's async results as follows: +\begin{itemize} +\item +For a value completion, +the result datums are returned in an engaged \tcode{optional} object +that contains a \tcode{variant} of \tcode{tuple}s. +\item +For an error completion, an exception is thrown. +\item +For a stopped completion, a disengaged \tcode{optional} object is returned. +\end{itemize} +\end{itemize} + +\rSec1[exec.util]{Sender/receiver utilities} + +\rSec2[exec.util.cmplsig]{\tcode{execution::completion_signatures}} + +\pnum +\tcode{completion_signatures} is a type +that encodes a set of completion signatures\iref{exec.async.ops}. + +\pnum +\begin{example} +\begin{codeblock} +struct my_sender { + using sender_concept = sender_t; + using completion_signatures = + execution::completion_signatures< + set_value_t(), + set_value_t(int, float), + set_error_t(exception_ptr), + set_error_t(error_code), + set_stopped_t()>; +}; +\end{codeblock} +Declares \tcode{my_sender} to be a sender +that can complete by calling one of the following +for a receiver expression \tcode{rcvr}: +\begin{itemize} +\item \tcode{set_value(rcvr)} +\item \tcode{set_value(rcvr, int\{...\}, float\{...\})} +\item \tcode{set_error(rcvr, exception_ptr\{...\})} +\item \tcode{set_error(rcvr, error_code\{...\})} +\item \tcode{set_stopped(rcvr)} +\end{itemize} +\end{example} + +\pnum +This subclause makes use of the following exposition-only entities: +\begin{codeblock} +template + concept @\defexposconcept{completion-signature}@ = @\seebelow@; +\end{codeblock} + +\pnum +A type \tcode{Fn} satisfies \exposconcept{completion-signature} +if and only if it is a function type with one of the following forms: +\begin{itemize} +\item +\tcode{set_value_t(Vs...)}, +where \tcode{Vs} is a pack of object or reference types. +\item +\tcode{set_error_t(Err)}, +where \tcode{Err} is an object or reference type. +\item +\tcode{set_stopped_t()} +\end{itemize} + +\pnum +\begin{codeblock} +template + struct @\exposid{indirect-meta-apply}@ { + template class T, class... As> + using @\exposid{meta-apply}@ = T; // \expos + }; + +template + concept @\defexposconcept{always-true}@ = true; // \expos + +template class Tuple, + template class Variant> + using @\exposid{gather-signatures}@ = @\seebelow@; +\end{codeblock} + +\pnum +Let \tcode{Fns} be a pack of the arguments of +the \tcode{completion_signatures} specialization named by \tcode{Completions}, +let \tcode{TagFns} be a pack of the function types in \tcode{Fns} +whose return types are \tcode{Tag}, and +let $\tcode{Ts}_n$ be a pack of the function argument types +in the $n$-th type in \tcode{TagFns}. +Then, given two variadic templates \tcode{Tuple} and \tcode{Variant}, +the type \tcode{\exposid{gather-signatures}} +names the type +\begin{codeblock} +@\exposid{META-APPLY}@(Variant, @\exposid{META-APPLY}@(Tuple, Ts@$_0$@...), + @\itcorr[1]\exposid{META-APPLY}@(Tuple, Ts@$_1$@...), + @\itcorr[1]\ldots@, + @\itcorr[1]\exposid{META-APPLY}@(Tuple, Ts@$_{m-1}$@...)) +\end{codeblock} +where $m$ is the size of the pack \tcode{TagFns} and +\tcode{META-APPLY(T, As...)} is equivalent to: +\begin{codeblock} +typename @\exposid{indirect-meta-apply}@<@\exposid{always-true}@>::template @\exposid{meta-apply}@ +\end{codeblock} + +\pnum +\begin{note} +The purpose of \exposid{META-APPLY} is to make it valid +to use non-variadic templates as \tcode{Variant} and \tcode{Tuple} arguments +to \exposid{gather-signatures}. +\end{note} + +\pnum +\begin{codeblock} +namespace std::execution { + template<@\exposconcept{completion-signature}@... Fns> + struct completion_signatures {}; + + template, + template class Tuple = @\exposid{decayed-tuple}@, + template class Variant = @\exposid{variant-or-empty}@> + requires @\libconcept{sender_in}@ + using value_types_of_t = + @\exposid{gather-signatures}@, Tuple, Variant>; + + template, + template class Variant = @\exposid{variant-or-empty}@> + requires @\libconcept{sender_in}@ + using error_types_of_t = + @\exposid{gather-signatures}@, + type_identity_t, Variant>; + + template> + requires @\libconcept{sender_in}@ + constexpr bool sends_stopped = + !@\libconcept{same_as}@<@\exposid{type-list}@<>, + @\exposid{gather-signatures}@, + @\exposid{type-list}@, @\exposid{type-list}@>>; +} +\end{codeblock} + +\rSec2[exec.util.cmplsig.trans]{\tcode{execution::transform_completion_signatures}} + +\pnum +\tcode{transform_completion_signatures} is an alias template +used to transform one set of completion signatures into another. +It takes a set of completion signatures and +several other template arguments +that apply modifications to each completion signature in the set +to generate a new specialization of \tcode{completion_signature}s. +\pnum +\begin{example} +Given a sender \tcode{Sndr} and an environment \tcode{Env}, +adapt the completion signatures of \tcode{Sndr} by +lvalue-ref qualifying the values, +adding an additional \tcode{exception_ptr} error completion +if it is not already there, and +leaving the other completion signatures alone. +\begin{codeblock} +template + using my_set_value_t = + completion_signatures< + set_value_t(add_lvalue_reference_t...)>; + +using my_completion_signatures = + transform_completion_signatures< + completion_signatures_of_t, + completion_signatures, + my_set_value_t>; +\end{codeblock} +\end{example} + +\pnum +This subclause makes use of the following exposition-only entities: +\begin{codeblock} +template + using @\exposid{default-set-value}@ = + completion_signatures; + +template + using @\exposid{default-set-error}@ = + completion_signatures; +\end{codeblock} + +\pnum +\begin{codeblock} +namespace std::execution { + template<@\exposconcept{valid-completion-signatures}@ InputSignatures, + @\exposconcept{valid-completion-signatures}@ AdditionalSignatures = completion_signatures<>, + template class SetValue = @\exposid{default-set-value}@, + template class SetError = @\exposid{default-set-error}@, + @\exposconcept{valid-completion-signatures}@ SetStopped = completion_signatures> + using transform_completion_signatures = completion_signatures<@\seebelow@>; +} +\end{codeblock} + +\pnum +\tcode{SetValue} shall name an alias template +such that for any pack of types \tcode{As}, +the type \tcode{SetValue} is either ill-formed or else +\tcode{\exposconcept{valid-completion-signatures}>} is satisfied. +\tcode{SetError} shall name an alias template +such that for any type \tcode{Err}, +\tcode{SetError} is either ill-formed or else +\tcode{\exposconcept{valid-completion-signatures}>} is satisfied. + +\pnum +Let \tcode{Vs} be a pack of the types in the \exposid{type-list} named by +\tcode{\exposid{gather-signatures}}. + +\pnum +Let \tcode{Es} be a pack of the types in the \exposid{type-list} named by +\tcode{\exposid{gather-signatures}}, +where \exposid{error-list} is an alias template +such that \tcode{\exposid{error-list}<\linebreak Ts...>} is +\tcode{\exposid{type-list}...>}. + +\pnum +Let \tcode{Ss} name the type \tcode{completion_signatures<>} if +\tcode{\exposid{gather-signatures}} +is an alias for the type \tcode{\exposid{type-list}<>}; +otherwise, \tcode{SetStopped}. + +\pnum +If any of the above types are ill-formed, +then +\begin{codeblock} +transform_completion_signatures +\end{codeblock} +is ill-formed. +Otherwise, +\begin{codeblock} +transform_completion_signatures +\end{codeblock} +is the type \tcode{completion_signatures} +where \tcode{Sigs...} is the unique set of types in all the template arguments +of all the \tcode{completion_signatures} specializations in the set +\tcode{AdditionalSignatures}, \tcode{Vs...}, \tcode{Es...}, \tcode{Ss}. + +\rSec1[exec.envs]{Queryable utilities} + +\rSec2[exec.prop]{Class template \tcode{prop}} + +\begin{codeblock} +namespace std::execution { + template + struct @\libglobal{prop}@ { + QueryTag @\exposid{query_}@; // \expos + ValueType @\exposid{value_}@; // \expos + + constexpr const ValueType& query(QueryTag) const noexcept { + return @\exposid{value_}@; + } + }; + + template + prop(QueryTag, ValueType) -> prop>; +} +\end{codeblock} + +\pnum +Class template \tcode{prop} is for building a queryable object +from a query object and a value. + +\pnum +\mandates +\tcode{\exposconcept{callable}>} +is modeled, +where \exposid{prop-like} is the following exposition-only class template: +\begin{codeblock} +template +struct @\exposid{prop-like}@ { // \expos + const ValueType& query(auto) const noexcept; +}; +\end{codeblock} + +\pnum +\begin{example} +\begin{codeblock} +template<@\libconcept{sender}@ Sndr> +sender auto parameterize_work(Sndr sndr) { + // Make an environment such that \tcode{get_allocator(env)} returns a reference to a copy of \tcode{my_alloc\{\}}. + auto e = prop(get_allocator, my_alloc{}); + + // Parameterize the input sender so that it will use our custom execution environment. + return write_env(sndr, e); +} +\end{codeblock} +\end{example} + +\pnum +Specializations of \tcode{prop} are not assignable. + +\rSec2[exec.env]{Class template \tcode{env}} + +\begin{codeblock} +namespace std::execution { + template<@\exposconcept{queryable}@... Envs> + struct @\libglobal{env}@ { + Envs@$_0$@ @$\exposid{envs}_0$@; // \expos + Envs@$_1$@ @$\exposid{envs}_1$@; // \expos + @\vdots@ + Envs@$_{n-1}$@ @$\exposid{envs}_{n-1}$@; // \expos + + template + constexpr decltype(auto) query(QueryTag q) const noexcept(@\seebelow@); + }; + + template + env(Envs...) -> env...>; +} +\end{codeblock} + +\pnum +The class template \tcode{env} is used to construct a queryable object +from several queryable objects. +Query invocations on the resulting object are resolved +by attempting to query each subobject in lexical order. + +\pnum +Specializations of \tcode{env} are not assignable. + +\pnum +It is unspecified +whether \tcode{env} supports initialization +using a parenthesized \grammarterm{expression-list}\iref{dcl.init}, +unless the \grammarterm{expression-list} consist of +a single element of type (possibly const) \tcode{env}. + +\pnum +\begin{example} +\begin{codeblock} +template<@\libconcept{sender}@ Sndr> +sender auto parameterize_work(Sndr sndr) { + // Make an environment such that: + // \tcode{get_allocator(env)} returns a reference to a copy of \tcode{my_alloc\{\}} + // \tcode{get_scheduler(env)} returns a reference to a copy of \tcode{my_sched\{\}} + auto e = env{prop(get_allocator, my_alloc{}), + prop(get_scheduler, my_sched{})}; + + // Parameterize the input sender so that it will use our custom execution environment. + return write_env(sndr, e); +} +\end{codeblock} +\end{example} + +\indexlibrarymember{query}{env}% +\begin{itemdecl} +template +constexpr decltype(auto) query(QueryTag q) const noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \exposconcept{has-query} be the following exposition-only concept: +\begin{codeblock} +template + concept @\defexposconcept{has-query}@ = // \expos + requires (const Env& env) { + env.query(QueryTag()); + }; +\end{codeblock} + +\pnum +Let \exposid{fe} be the first element of +$\exposid{envs}_0$, $\exposid{envs}_1$, $\dotsc$, $\exposid{envs}_{n-1}$ +such that the expression \tcode{\exposid{fe}.query(q)} is well-formed. + +\pnum +\constraints +\tcode{(\exposconcept{has-query} || ...)} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return \exposid{fe}.query(q);} + +\pnum +\remarks +The expression in the \tcode{noexcept} clause is equivalent +to \tcode{noexcept(\exposid{fe}.query(q))}. +\end{itemdescr} + +\rSec1[exec.ctx]{Execution contexts} + +\rSec2[exec.run.loop]{\tcode{execution::run_loop}} + +\rSec3[exec.run.loop.general]{General} + +\pnum +A \tcode{run_loop} is an execution resource on which work can be scheduled. +It maintains a thread-safe first-in-first-out queue of work. +Its \tcode{run} member function removes elements from the queue and +executes them in a loop on the thread of execution that calls \tcode{run}. + +\pnum +A \tcode{run_loop} instance has an associated \defn{count} +that corresponds to the number of work items that are in its queue. +Additionally, a \tcode{run_loop} instance has an associated state +that can be one of +\defn{starting}, \defn{running}, \defn{finishing}, or \defn{finished}. + +\pnum +Concurrent invocations of the member functions of \tcode{run_loop} +other than \tcode{run} and its destructor do not introduce data races. +The member functions +\exposid{pop-front}, \exposid{push-back}, and \tcode{finish} +execute atomically. + +\pnum +\recommended +Implementations should use an intrusive queue of operation states +to hold the work units to make scheduling allocation-free. + +\begin{codeblock} +namespace std::execution { + class @\libglobal{run_loop}@ { + // \ref{exec.run.loop.types}, associated types + class @\exposid{run-loop-scheduler}@; // \expos + class @\exposid{run-loop-sender}@; // \expos + struct @\exposid{run-loop-opstate-base}@ { // \expos + virtual void @\exposid{execute}@() = 0; // \expos + run_loop* @\exposid{loop}@; // \expos + @\exposid{run-loop-opstate-base}@* @\exposid{next}@; // \expos + }; + template + using @\exposid{run-loop-opstate}@ = @\unspec@; // \expos + + // \ref{exec.run.loop.members}, member functions + @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); // \expos + void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*); // \expos + + public: + // \ref{exec.run.loop.ctor}, constructor and destructor + run_loop() noexcept; + run_loop(run_loop&&) = delete; + ~run_loop(); + + // \ref{exec.run.loop.members}, member functions + @\exposid{run-loop-scheduler}@ get_scheduler(); + void run(); + void finish(); + }; +} +\end{codeblock} + +\rSec3[exec.run.loop.types]{Associated types} + +\begin{itemdecl} +class @\exposid{run-loop-scheduler}@; +\end{itemdecl} + +\pnum +\exposid{run-loop-scheduler} is an unspecified type +that models \libconcept{scheduler}. + +\pnum +Instances of \exposid{run-loop-scheduler} remain valid +until the end of the lifetime of the \tcode{run_loop} instance +from which they were obtained. + +\pnum +Two instances of \exposid{run-loop-scheduler} compare equal +if and only if they were obtained from the same \tcode{run_loop} instance. + +\pnum +Let \exposid{sch} be an expression of type \exposid{run-loop-scheduler}. +The expression \tcode{schedule(\exposid{sch})} +has type \exposid{run-loop-\newline sender} and +is not potentially-throwing if \exposid{sch} is not potentially-throwing. + +\begin{itemdecl} +class @\exposid{run-loop-sender}@; +\end{itemdecl} + +\pnum +\exposid{run-loop-sender} is an exposition-only type +that satisfies \libconcept{sender}. +For any type \tcode{Env}, +\tcode{completion_signatures_of_t<\exposid{run-loop-sender}, Env>} is +\begin{codeblock} +completion_signatures +\end{codeblock} + +\pnum +An instance of \exposid{run-loop-sender} remains valid +until the end of the lifetime of its associated \tcode{run_loop} instance. + +\pnum +Let \exposid{sndr} be an expression of type \exposid{run-loop-sender}, +let \exposid{rcvr} be an expression +such that \tcode{\libconcept{receiver_of}} is \tcode{true} +where \tcode{CS} is the \tcode{completion_signatures} specialization above. +Let \tcode{C} be either \tcode{set_value_t} or \tcode{set_stopped_t}. +Then: +\begin{itemize} +\item +The expression \tcode{connect(\exposid{sndr}, \exposid{rcvr})} +has type \tcode{\exposid{run-loop-opstate}>} +and is potentially-throwing if and only if +\tcode{(void(\exposid{sndr}), auto(\exposid{rcvr}))} is potentially-throwing. +\item +The expression \tcode{get_completion_scheduler(get_env(\exposid{sndr}))} +is potentially-throwing if and only if \exposid{sndr} is potentially-throwing, +has type \exposid{run-loop-scheduler}, and +compares equal to the \exposid{run-loop-\newline scheduler} instance +from which \exposid{sndr} was obtained. +\end{itemize} + +\begin{itemdecl} +template + struct @\exposid{run-loop-opstate}@; +\end{itemdecl} + +\pnum +\tcode{\exposid{run-loop-opstate}} +inherits privately and unambiguously from \exposid{run-loop-opstate-base}. + +\pnum +Let $o$ be a non-const lvalue of type \tcode{\exposid{run-loop-opstate}}, +and let \tcode{REC($o$)} be a non-const lvalue reference to an instance of type \tcode{Rcvr} +that was initialized with the expression \exposid{rcvr} +passed to the invocation of connect that returned $o$. +Then: +\begin{itemize} +\item +The object to which \tcode{\exposid{REC}($o$)} refers +remains valid for the lifetime of the object to which $o$ refers. +\item +The type \tcode{\exposid{run-loop-opstate}} overrides +\tcode{\exposid{run-loop-opstate-base}::\exposid{execute}()} +such that \tcode{$o$.\exposid{exe\-cute}()} is equivalent to: +\begin{codeblock} +if (get_stop_token(@\exposid{REC}@(@$o$@)).stop_requested()) { + set_stopped(std::move(@\exposid{REC}@(@$o$@))); +} else { + set_value(std::move(@\exposid{REC}@(@$o$@))); +} +\end{codeblock} +\item +The expression \tcode{start($o$)} is equivalent to: +\begin{codeblock} +try { + @$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@)); +} catch(...) { + set_error(std::move(@\exposid{REC}@(@$o$@)), current_exception()); +} +\end{codeblock} +\end{itemize} + +\rSec3[exec.run.loop.ctor]{Constructor and destructor} + +\indexlibraryctor{run_loop}% +\begin{itemdecl} +run_loop() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\exposid{count} is \tcode{0} and \exposid{state} is \exposid{starting}. +\end{itemdescr} + +\indexlibrarydtor{run_loop}% +\begin{itemdecl} +~run_loop(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \exposid{count} is not \tcode{0} or if \exposid{state} is \exposid{running}, +invokes \tcode{terminate}\iref{except.terminate}. +Otherwise, has no effects. +\end{itemdescr} + +\rSec3[exec.run.loop.members]{Member functions} + +\begin{itemdecl} +@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Blocks\iref{defns.block} until one of the following conditions is \tcode{true}: +\begin{itemize} +\item +\exposid{count} is \tcode{0} and \exposid{state} is \exposid{finishing}, +in which case \exposid{pop-front} sets \exposid{state} to \exposid{finished} +and returns \tcode{nullptr}; or +\item +\exposid{count} is greater than \tcode{0}, +in which case an item is removed from the front of the queue, +\exposid{count} is decremented by \tcode{1}, and +the removed item is returned. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Adds \tcode{item} to the back of the queue and +increments \exposid{count} by \tcode{1}. + +\pnum +\sync +This operation synchronizes with +the \exposid{pop-front} operation that obtains \tcode{item}. +\end{itemdescr} + +\indexlibrarymember{get_scheduler}{run_loop}% +\begin{itemdecl} +@\exposid{run-loop-scheduler}@ get_scheduler(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An instance of \exposid{run-loop-scheduler} +that can be used to schedule work onto this \tcode{run_loop} instance. +\end{itemdescr} + +\indexlibrarymember{run}{run_loop}% +\begin{itemdecl} +void run(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\exposid{state} is either \exposid{starting} or \exposid{finishing}. + +\pnum +\effects +If \exposid{state} is \exposid{starting}, +sets the \exposid{state} to \exposid{running}, +otherwise leaves \exposid{state} unchanged. +Then, equivalent to: +\begin{codeblock} +while (auto* op = @\exposid{pop-front}@()) { + op->@\exposid{execute}@(); +} +\end{codeblock} + +\pnum +\remarks +When \exposid{state} changes, it does so without introducing data races. +\end{itemdescr} + +\indexlibrarymember{finish}{run_loop}% +\begin{itemdecl} +void finish(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\exposid{state} is either \exposid{starting} or \exposid{running}. + +\pnum +\effects +Changes \exposid{state} to \exposid{finishing}. + +\pnum +\sync +\tcode{finish} synchronizes with the \exposid{pop-front} operation +that returns \tcode{nullptr}. +\end{itemdescr} + +\rSec1[exec.coro.util]{Coroutine utilities} + +\rSec2[exec.as.awaitable]{\tcode{execution::as_awaitable}} + +\pnum +\tcode{as_awaitable} transforms an object into one +that is awaitable within a particular coroutine. +Subclause \ref{exec.coro.util} makes use of +the following exposition-only entities: +\begin{codeblock} +namespace std::execution { + template + concept @\defexposconcept{awaitable-sender}@ = + @\exposconcept{single-sender}@> && + @\libconcept{sender_to}@ && // \seebelow + requires (Promise& p) { + { p.unhandled_stopped() } -> @\libconcept{convertible_to}@>; + }; + + template + class @\exposidnc{sender-awaitable}@; // \expos +} +\end{codeblock} + +\pnum +The type \tcode{\exposid{sender-awaitable}} is equivalent to: + +\begin{codeblock} +namespace std::execution { + template + class @\exposidnc{sender-awaitable}@ { + struct @\exposidnc{unit}@ {}; // \expos + using @\exposidnc{value-type}@ = // \expos + @\exposidnc{single-sender-value-type}@>; + using @\exposidnc{result-type }@= // \expos + conditional_t, unit, @\exposid{value-type}@>; + struct @\exposidnc{awaitable-receiver}@; // \expos + + variant @\exposidnc{result}@{}; // \expos + connect_result_t @\exposidnc{state}@; // \expos + + public: + @\exposid{sender-awaitable}@(Sndr&& sndr, Promise& p); + static constexpr bool await_ready() noexcept { return false; } + void await_suspend(coroutine_handle) noexcept { start(@\exposid{state}@); } + @\exposid{value-type}@ await_resume(); + }; +} +\end{codeblock} + +\pnum +\exposid{awaitable-receiver} is equivalent to: +\begin{codeblock} +struct @\exposid{awaitable-receiver}@ { + using receiver_concept = receiver_t; + variant* @\exposidnc{result-ptr}@; // \expos + coroutine_handle @\exposidnc{continuation}@; // \expos + // \seebelow +}; +\end{codeblock} + +\pnum +Let \tcode{rcvr} be an rvalue expression of type \exposid{awaitable-receiver}, +let \tcode{crcvr} be a const lvalue that refers to \tcode{rcvr}, +let \tcode{vs} be a pack of subexpressions, and +let \tcode{err} be an expression of type \tcode{Err}. Then: +\begin{itemize} +\item +If \tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} +is satisfied, +the expression \tcode{set_value(\newline rcvr, vs...)} is equivalent to: +\begin{codeblock} +try { + rcvr.@\exposid{result-ptr}@->template emplace<1>(vs...); +} catch(...) { + rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception()); +} +rcvr.@\exposid{continuation}@.resume(); +\end{codeblock} +Otherwise, \tcode{set_value(rcvr, vs...)} is ill-formed. +\item +The expression \tcode{set_error(rcvr, err)} is equivalent to: +\begin{codeblock} +rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err)); // see \ref{exec.general} +rcvr.@\exposid{continuation}@.resume(); +\end{codeblock} +\item +The expression \tcode{set_stopped(rcvr)} is equivalent to: +\begin{codeblock} +static_cast>(rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume(); +\end{codeblock} +\item +For any expression \tcode{tag} +whose type satisfies \exposconcept{forwarding-query} and +for any pack of subexpressions \tcode{as}, +\tcode{get_env(crcvr).query(tag, as...)} is expression-equivalent to: +\begin{codeblock} +tag(get_env(as_const(crcvr.@\exposid{continuation}@.promise())), as...) +\end{codeblock} +\end{itemize} + +\begin{itemdecl} +@\exposid{sender-awaitable}@(Sndr&& sndr, Promise& p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{state} with +\begin{codeblock} +connect(std::forward(sndr), + @\exposid{awaitable-receiver}@{addressof(result), coroutine_handle::from_promise(p)}) +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +@\exposid{value-type}@ await_resume(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (@\exposid{result}@.index() == 2) + rethrow_exception(get<2>(@\exposid{result}@)); +if constexpr (!is_void_v<@\exposid{value-type}@>) + return std::forward<@\exposid{value-type}@>(get<1>(@\exposid{result}@)); +\end{codeblock} +\end{itemdescr} + +\pnum +\tcode{as_awaitable} is a customization point object. +For subexpressions \tcode{expr} and \tcode{p} +where \tcode{p} is an lvalue, +\tcode{Expr} names the type \tcode{decltype((expr))} and +\tcode{Promise} names the type \tcode{decay_t}, +\tcode{as_awaitable(expr, p)} is expression-equivalent to, +except that the evaluations of \tcode{expr} and \tcode{p} +are indeterminately sequenced: +\begin{itemize} +\item +\tcode{expr.as_awaitable(p)} if that expression is well-formed. + +\mandates +\tcode{\exposconcept{is-awaitable}} is \tcode{true}, +where \tcode{A} is the type of the expression above. +\item +Otherwise, \tcode{(void(p), expr)} +if \tcode{\exposconcept{is-awaitable}} is \tcode{true}, +where \tcode{U} is an unspecified class type +that is not \tcode{Promise} and +that lacks a member named \tcode{await_transform}. + +\expects +\tcode{\exposconcept{is-awaitable}} is \tcode{true} and +the expression \tcode{co_await expr} +in a coroutine with promise type \tcode{U} is expression-equivalent to +the same expression in a coroutine with promise type \tcode{Promise}. +\item +Otherwise, \tcode{\exposid{sender-awaitable}\{expr, p\}} +if \tcode{\exposconcept{awaitable-sender}} is \tcode{true}. +\item +Otherwise, \tcode{(void(p), expr)}. +\end{itemize} + +\rSec2[exec.with.awaitable.senders]{\tcode{execution::with_awaitable_senders}} + +\pnum +\tcode{with_awaitable_senders}, +when used as the base class of a coroutine promise type, +makes senders awaitable in that coroutine type. + +In addition, it provides a default implementation of \tcode{unhandled_stopped} +such that if a sender completes by calling \tcode{set_stopped}, +it is treated as if an uncatchable "stopped" exception were thrown +from the \grammarterm{await-expression}. +\begin{note} +The coroutine is never resumed, and +the \tcode{unhandled_stopped} of the coroutine caller's promise type is called. +\end{note} + +\begin{codeblock} +namespace std::execution { + template<@\exposconcept{class-type}@ Promise> + struct @\libglobal{with_awaitable_senders}@ { + template + requires (!@\libconcept{same_as}@) + void set_continuation(coroutine_handle h) noexcept; + + coroutine_handle<> @\libmember{continuation}{with_awaitable_senders}@() const noexcept { return @\exposid{continuation}@; } + + coroutine_handle<> @\libmember{unhandled_stopped}{with_awaitable_senders}@() noexcept { + return @\exposid{stopped-handler}@(@\exposid{continuation}@.address()); + } + + template + @\seebelow@ await_transform(Value&& value); + + private: + [[noreturn]] static coroutine_handle<> + @\exposid{default-unhandled-stopped}@(void*) noexcept { // \expos + terminate(); + } + coroutine_handle<> @\exposid{continuation}@{}; // \expos + coroutine_handle<> (*@\exposid{stopped-handler}@)(void*) noexcept = // \expos + &@\exposid{default-unhandled-stopped}@; + }; +} +\end{codeblock} + +\indexlibrarymember{set_continuation}{with_awaitable_senders}% +\begin{itemdecl} +template + requires (!@\libconcept{same_as}@) +void set_continuation(coroutine_handle h) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{continuation}@ = h; +if constexpr ( requires(OtherPromise& other) { other.unhandled_stopped(); } ) { + @\exposid{stopped-handler}@ = [](void* p) noexcept -> coroutine_handle<> { + return coroutine_handle::from_address(p) + .promise().unhandled_stopped(); + }; +} else { + @\exposid{stopped-handler}@ = &@\exposid{default-unhandled-stopped}@; +} +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{await_transform}{with_awaitable_senders}% +\begin{itemdecl} +template +@\exposid{call-result-t}@ await_transform(Value&& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return as_awaitable(std::forward(value), static_cast(*this)); +\end{codeblock} +\end{itemdescr} diff --git a/source/expressions.tex b/source/expressions.tex index d44a832ce4..aed3d0b9dc 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -53,7 +53,7 @@ considered where necessary to convert the operands to types appropriate for the built-in operator. If a built-in operator is selected, such conversions will be applied to the operands before the operation is -considered further according to the rules in subclause \ref{expr.compound}; +considered further according to the rules in \ref{expr.compound}; see~\ref{over.match.oper}, \ref{over.built}. \pnum @@ -131,7 +131,7 @@ \begin{footnote} The cast and assignment operators must still perform their specific conversions as described in~\ref{expr.type.conv}, \ref{expr.cast}, -\ref{expr.static.cast} and~\ref{expr.ass}. +\ref{expr.static.cast} and~\ref{expr.assign}. \end{footnote} \rSec1[expr.prop]{Properties of expressions} @@ -233,13 +233,11 @@ A prvalue whose result is the value \placeholder{V} is sometimes said to have or name the value \placeholder{V}. The \defn{result object} of a prvalue is the object initialized by the prvalue; -a non-discarded prvalue -that is used to compute the value of an operand of a built-in operator -or a prvalue that has type \cv{}~\keyword{void} +a prvalue that has type \cv{}~\keyword{void} has no result object. \begin{note} Except when the prvalue is the operand of a \grammarterm{decltype-specifier}, -a prvalue of class or array type always has a result object. +a prvalue of object type always has a result object. For a discarded prvalue that has type other than \cv{}~\keyword{void}, a temporary object is materialized; see \ref{expr.context}. \end{note} @@ -266,9 +264,11 @@ \end{note} \pnum -Whenever a prvalue appears as an operand of an operator that -expects a glvalue for that operand, the -temporary materialization conversion\iref{conv.rval} is +Unless otherwise specified\iref{expr.reinterpret.cast, expr.const.cast}, +whenever a prvalue +that is not the result of the lvalue-to-rvalue conversion\iref{conv.lval} +appears as an operand of an operator, +the temporary materialization conversion\iref{conv.rval} is applied to convert the expression to an xvalue. \pnum @@ -296,31 +296,32 @@ \begin{note} A program that attempts to modify an object through a nonmodifiable lvalue or through an rvalue -is ill-formed\iref{expr.ass,expr.post.incr,expr.pre.incr}. +is ill-formed\iref{expr.assign,expr.post.incr,expr.pre.incr}. \end{note} \pnum +An object of dynamic type $\tcode{T}_\text{obj}$ is +\defn{type-accessible} through a glvalue of type $\tcode{T}_\text{ref}$ +if $\tcode{T}_\text{ref}$ is similar\iref{conv.qual} to: +\begin{itemize} +\item $\tcode{T}_\text{obj}$, + +\item a type that is the signed or unsigned type corresponding to $\tcode{T}_\text{obj}$, or + +\item a \keyword{char}, \tcode{\keyword{unsigned} \keyword{char}}, or \tcode{std::byte} type. +\end{itemize} If a program attempts to access\iref{defns.access} the stored value of an object through a glvalue -whose type is not similar\iref{conv.qual} to -one of the following types the behavior is -undefined: +through which it is not type-accessible, +the behavior is undefined. \begin{footnote} The intent of this list is to specify those circumstances in which an object can or cannot be aliased. \end{footnote} -\begin{itemize} -\item the dynamic type of the object, - -\item a type that is the signed or unsigned type corresponding to the -dynamic type of the object, or - -\item a \keyword{char}, \tcode{\keyword{unsigned} \keyword{char}}, or \tcode{std::byte} type. -\end{itemize} If a program invokes a defaulted copy/move constructor or copy/move assignment operator for a union of type \tcode{U} with a glvalue argument -that does not denote an object of type \cv{}~\keyword{U} within its lifetime, +that does not denote an object of type \cv{}~\tcode{U} within its lifetime, the behavior is undefined. \begin{note} In C, an entire object of structure type can be accessed, e.g., using assignment. @@ -334,9 +335,13 @@ \indextext{expression!reference}% If an expression initially has the type ``reference to \tcode{T}''\iref{dcl.ref,dcl.init.ref}, the type is adjusted to -\tcode{T} prior to any further analysis. The expression designates the -object or function denoted by the reference, and the expression -is an lvalue or an xvalue, depending on the expression. +\tcode{T} prior to any further analysis; +the value category of the expression is not altered. +Let $X$ be the object or function denoted by the reference. +If a pointer to $X$ would be valid in +the context of the evaluation of the expression\iref{basic.fundamental}, +the result designates $X$; +otherwise, the behavior is undefined. \begin{note} Before the lifetime of the reference has started or after it has ended, the behavior is undefined (see~\ref{basic.life}). @@ -432,7 +437,8 @@ \pnum \label{term.unevaluated.operand}% In some contexts, \defnx{unevaluated operands}{unevaluated operand} -appear\iref{expr.prim.req, +appear\iref{expr.prim.req.simple, +expr.prim.req.compound, expr.typeid, expr.sizeof, expr.unary.noexcept, @@ -621,7 +627,7 @@ prvalue is \tcode{T}. \begin{footnote} In \Cpp{} class and array prvalues can have cv-qualified types. -This differs from ISO C, in which non-lvalues never have +This differs from C, in which non-lvalues never have cv-qualified types. \end{footnote} @@ -669,11 +675,29 @@ the glvalue. \item Otherwise, if the object to which the glvalue refers contains an invalid -pointer value\iref{basic.stc.dynamic.deallocation}, the behavior is +pointer value\iref{basic.compound}, the behavior is \impldef{lvalue-to-rvalue conversion of an invalid pointer value}. -\item Otherwise, the object indicated by the glvalue is read\iref{defns.access}, -and the value contained in the object is the prvalue result. +\item Otherwise, if the bits in the value representation of +the object to which the glvalue refers +are not valid for the object's type, the behavior is undefined. +\begin{example} +\begin{codeblock} +bool f() { + bool b = true; + char c = 42; + memcpy(&b, &c, 1); + return b; // undefined behavior if \tcode{42} is not a valid value representation for \keyword{bool} +} +\end{codeblock} +\end{example} + +\item Otherwise, the object indicated by the glvalue is read\iref{defns.access}. +Let \tcode{V} be the value contained in the object. +If \tcode{T} is an integer type, +the prvalue result is +the value of type \tcode{T} congruent\iref{basic.fundamental} to \tcode{V}, and +\tcode{V} otherwise. \end{itemize} \pnum @@ -1030,16 +1054,26 @@ The pointer value\iref{basic.compound} is unchanged by this conversion. \pnum -A prvalue of type ``pointer to \cv{} \tcode{D}'', where \tcode{D} +A prvalue \tcode{v} of type ``pointer to \cv{} \tcode{D}'', where \tcode{D} is a complete class type, can be converted to a prvalue of type ``pointer to \cv{} \tcode{B}'', where \tcode{B} is a base class\iref{class.derived} of \tcode{D}. If \tcode{B} is an inaccessible\iref{class.access} or ambiguous\iref{class.member.lookup} base class of \tcode{D}, a program -that necessitates this conversion is ill-formed. The result of the -conversion is a pointer to the base class subobject of the derived class -object. The null pointer value is converted to the null pointer value of -the destination type. +that necessitates this conversion is ill-formed. +If \tcode{v} is a null pointer value, +the result is a null pointer value. +Otherwise, +if \tcode{B} is a virtual base class of \tcode{D} and +\tcode{v} does not point to an object +whose type is similar\iref{conv.qual} to \tcode{D} and +that is +within its lifetime or +within its period of construction or destruction\iref{class.cdtor}, +the behavior is undefined. +Otherwise, +the result is a pointer to the base class subobject of +the derived class object. \rSec2[conv.mem]{Pointer-to-member conversions} @@ -1144,11 +1178,14 @@ \item If either operand is of scoped enumeration type\iref{dcl.enum}, no conversions are performed; if the other operand does not have the same type, the expression is ill-formed. +\item Otherwise, if one operand is of enumeration type and the other operand is +of a different enumeration type or a floating-point type, the expression is +ill-formed. \item Otherwise, if either operand is of floating-point type, the following rules are applied: \begin{itemize} \item -If both operands have the same type, no further conversion is needed. +If both operands have the same type, no further conversion is performed. \item Otherwise, if one of the operands is of a non-floating-point type, that operand is converted to the type of @@ -1197,16 +1234,11 @@ \end{itemize} \end{itemize} -\pnum -If one operand is of enumeration type -and the other operand is of -a different enumeration type or -a floating-point type, -this behavior is deprecated\iref{depr.arith.conv.enum}. - \rSec1[expr.prim]{Primary expressions}% \indextext{expression!primary|(} +\rSec2[expr.prim.grammar]{Grammar} + \begin{bnf} \nontermdef{primary-expression}\br literal\br @@ -1247,6 +1279,16 @@ A \grammarterm{lambda-expression} does not introduce a class scope. \end{note} +\pnum +If the expression \tcode{this} +appears within the predicate of a contract assertion\iref{basic.contract.general} +(including as the result of an implicit transformation\iref{expr.prim.id.general} +and including in the bodies of nested \grammarterm{lambda-expression}s) +and the current class +encloses the contract assertion, +\keyword{const} is combined with the \grammarterm{cv-qualifier-seq} +used to generate the resulting type (see below). + \pnum If a declaration declares a member function or member function template of a class \tcode{X}, the expression \keyword{this} is a prvalue of type ``pointer to @@ -1255,8 +1297,8 @@ between the optional \grammarterm{cv-qualifier-seq} and the end of the \grammarterm{function-definition}, \grammarterm{member-declarator}, or \grammarterm{declarator}. It shall not appear within -the declaration of either -a static member function or an explicit object member function +the declaration of +a static or explicit object member function of the current class (although its type and value category are defined within such member functions as they are within an implicit object member function). @@ -1325,7 +1367,8 @@ \begin{bnf} \nontermdef{id-expression}\br unqualified-id\br - qualified-id + qualified-id\br + pack-index-expression \end{bnf} \pnum @@ -1338,14 +1381,57 @@ operators\iref{expr.ref}. \end{note} +\pnum +If an \grammarterm{id-expression} $E$ denotes +a non-static non-type member of some class \tcode{C} at a point where +the current class\iref{expr.prim.this} is \tcode{X} and +\begin{itemize} +\item +$E$ is potentially evaluated or +\tcode{C} is \tcode{X} or a base class of \tcode{X}, and +\item +$E$ is not the \grammarterm{id-expression} of +a class member access expression\iref{expr.ref}, and +\item +if $E$ is a \grammarterm{qualified-id}, +$E$ is not the un-parenthesized operand of +the unary \tcode{\&} operator\iref{expr.unary.op}, +\end{itemize} +the \grammarterm{id-expression} is transformed into +a class member access expression using \tcode{(*this)} as the object expression. +If this transformation occurs +in the predicate of a precondition assertion of a constructor of \tcode{X} +or a postcondition assertion of a destructor of \tcode{X}, +the expression is ill-formed. +\begin{note} +If \tcode{C} is not \tcode{X} or a base class of \tcode{X}, +the class member access expression is ill-formed. +Also, if the \grammarterm{id-expression} occurs within +a static or explicit object member function, +the class member access is ill-formed. +\end{note} +This transformation does not apply in +the template definition context\iref{temp.dep.type}. +\begin{example} +\begin{codeblock} +struct C { + bool b; + C() pre(b) // error + pre(&this->b) // OK + pre(sizeof(b) > 0); // OK, \tcode{b} is not potentially evaluated. +}; +\end{codeblock} +\end{example} + \pnum If an \grammarterm{id-expression} $E$ denotes a member $M$ of an anonymous union\iref{class.union.anon} $U$: \begin{itemize} \item If $U$ is a non-static data member, -$E$ refers to $M$ as a member of the lookup context of the terminal name of $E$ (after any transformation to -a class member access expression\iref{class.mfct.non.static}). +$E$ refers to $M$ as a member of the lookup context of the terminal name of $E$ +(after any implicit transformation to +a class member access expression). \begin{example} \tcode{o.x} is interpreted as \tcode{o.$u$.x}, where $u$ names the anonymous union member. @@ -1367,13 +1453,11 @@ An \grammarterm{id-expression} that denotes a non-static data member or implicit object member function of a class can only be used: \begin{itemize} -\item as part of a class member access\iref{expr.ref} in which the +\item as part of a class member access +(after any implicit transformation (see above)) +in which the object expression refers to the member's class -\begin{footnote} -This also applies when the object expression -is an implicit \tcode{(*\keyword{this})}\iref{class.mfct.non.static}. -\end{footnote} or a class derived from that class, or @@ -1415,7 +1499,7 @@ \end{codeblock} In each case, the constraints of \tcode{f} are not satisfied. In the declaration of \tcode{p2}, -those constraints are required to be satisfied +those constraints need to be satisfied even though \tcode{f} is an unevaluated operand\iref{term.unevaluated.operand}. \end{example} @@ -1430,7 +1514,7 @@ conversion-function-id\br literal-operator-id\br \terminal{\~} type-name\br - \terminal{\~} decltype-specifier\br + \terminal{\~} computed-type-specifier\br template-id \end{bnf} @@ -1438,21 +1522,16 @@ \indextext{identifier}% An \grammarterm{identifier} is only an \grammarterm{id-expression} if it has -been suitably declared\iref{dcl.dcl} +been suitably declared\iref{dcl} or if it appears as part of a \grammarterm{declarator-id}\iref{dcl.decl}. -An \grammarterm{identifier} that names a coroutine parameter -refers to the copy of the parameter\iref{dcl.fct.def.coroutine}. \begin{note} For \grammarterm{operator-function-id}{s}, see~\ref{over.oper}; for \grammarterm{conversion-function-id}{s}, see~\ref{class.conv.fct}; for \grammarterm{literal-operator-id}{s}, see~\ref{over.literal}; for \grammarterm{template-id}{s}, see~\ref{temp.names}. -A \grammarterm{type-name} or \grammarterm{decltype-specifier} +A \grammarterm{type-name} or \grammarterm{computed-type-specifier} prefixed by \tcode{\~} denotes the destructor of the type so named; see~\ref{expr.prim.id.dtor}. -Within the definition of a non-static member function, an -\grammarterm{identifier} that names a non-static member is transformed to a -class member access expression\iref{class.mfct.non.static}. \end{note} \pnum @@ -1475,21 +1554,28 @@ \pnum The result is the entity denoted by the \grammarterm{unqualified-id}\iref{basic.lookup.unqual}. -If the \grammarterm{unqualified-id} appears -in a \grammarterm{lambda-expression} at program point $P$ and -the entity is a local entity\iref{basic.pre} or a variable declared by -an \grammarterm{init-capture}\iref{expr.prim.lambda.capture}, -then let $S$ be the \grammarterm{compound-statement} of -the innermost enclosing \grammarterm{lambda-expression} of $P$. -If naming the entity from outside of an unevaluated operand within $S$ -would refer to an entity -captured by copy in some intervening \grammarterm{lambda-expression}, -then let $E$ be the innermost such \grammarterm{lambda-expression}. + +\pnum +If \begin{itemize} \item -If there is such a \grammarterm{lambda-expression} and -if $P$ is in $E$'s function parameter scope -but not its \grammarterm{parameter-declaration-clause}, then +the \grammarterm{unqualified-id} +appears in a \grammarterm{lambda-expression} +at program point $P$, +\item +the entity is a local entity\iref{basic.pre} +or a variable declared by an \grammarterm{init-capture}\iref{expr.prim.lambda.capture}, +\item +naming the entity within the \grammarterm{compound-statement} of +the innermost enclosing \grammarterm{lambda-expression} of $P$, +but not in an unevaluated operand, would refer to an entity captured by copy +in some intervening \grammarterm{lambda-expression}, and +\item +$P$ is in the function parameter scope, +but not the \grammarterm{parameter-declaration-clause}, +of the innermost such \grammarterm{lambda-expression} $E$, +\end{itemize} +then the type of the expression is the type of a class member access expression\iref{expr.ref} naming the non-static data member @@ -1499,27 +1585,166 @@ If $E$ is not declared \keyword{mutable}, the type of such an identifier will typically be \keyword{const} qualified. \end{note} + +\pnum +Otherwise, +if the \grammarterm{unqualified-id} +names a coroutine parameter, +the type of the expression is +that of the copy of the parameter\iref{dcl.fct.def.coroutine}, +and the result is that copy. + +\pnum +Otherwise, +if the \grammarterm{unqualified-id} +names a result binding\iref{dcl.contract.res} +attached to a function \placeholder{f} +with return type \tcode{U}, +\begin{itemize} +\item +if \tcode{U} is ``reference to \tcode{T}'', +then the type of the expression is +\tcode{const T}; \item -Otherwise (if there is no such \grammarterm{lambda-expression} or -if $P$ either precedes $E$'s function parameter scope or -is in $E$'s \grammarterm{parameter-declaration-clause}), -the type of the expression is the type of the result. +otherwise, +the type of the expression is \tcode{const U}. \end{itemize} -\begin{note} -If the entity is a template parameter object for + +\pnum +Otherwise, +if the \grammarterm{unqualified-id} +appears in the predicate of a contract assertion $C$\iref{basic.contract} +and the entity is +\begin{itemize} +\item +a variable +declared outside of $C$ +of object type \tcode{T}, +\item +a variable or template parameter +declared outside of $C$ +of type ``reference to \tcode{T}'', or +\item +a structured binding +of type \tcode{T} +whose corresponding variable +is declared outside of $C$, +\end{itemize} +then the type of the expression is \keyword{const}~\tcode{T}. + +\pnum +\begin{example} +\begin{codeblock} +int n = 0; +struct X { bool m(); }; + +struct Y { + int z = 0; + + void f(int i, int* p, int& r, X x, X* px) + pre (++n) // error: attempting to modify const lvalue + pre (++i) // error: attempting to modify const lvalue + pre (++(*p)) // OK + pre (++r) // error: attempting to modify const lvalue + pre (x.m()) // error: calling non-const member function + pre (px->m()) // OK + pre ([=,&i,*this] mutable { + ++n; // error: attempting to modify const lvalue + ++i; // error: attempting to modify const lvalue + ++p; // OK, refers to member of closure type + ++r; // OK, refers to non-reference member of closure type + ++this->z; // OK, captured \tcode{*\keyword{this}} + ++z; // OK, captured \tcode{*\keyword{this}} + int j = 17; + [&]{ + int k = 34; + ++i; // error: attempting to modify const lvalue + ++j; // OK + ++k; // OK + }(); + return true; + }()); + + template + void g() + pre(++N) // error: attempting to modify prvalue + pre(++R) // error: attempting to modify const lvalue + pre(++(*P)); // OK + + int h() + post(r : ++r) // error: attempting to modify const lvalue + post(r: [=] mutable { + ++r; // OK, refers to member of closure type + return true; + }()); + + int& k() + post(r : ++r); // error: attempting to modify const lvalue +}; +\end{codeblock} +\end{example} + +\pnum +Otherwise, if the entity is a template parameter object for a template parameter of type \tcode{T}\iref{temp.param}, the type of the expression is \tcode{const T}. -\end{note} + +\pnum +In all other cases, the type of the expression is the type of the entity. + +\pnum \begin{note} The type will be adjusted as described in \ref{expr.type} if it is cv-qualified or is a reference type. \end{note} + +\pnum The expression is an xvalue if it is move-eligible (see below); an lvalue -if the entity is a function, variable, structured binding\iref{dcl.struct.bind}, data member, or +if the entity is a +function, +variable, +structured binding\iref{dcl.struct.bind}, +result binding\iref{dcl.contract.res}, +data member, or template parameter object; and a prvalue otherwise\iref{basic.lval}; it is a bit-field if the identifier designates a bit-field. + +\pnum +If an \grammarterm{id-expression} $E$ +appears in the predicate of +a function contract assertion attached to a function \placeholder{f} +and denotes +a function parameter of \placeholder{f} +and the implementation introduces any temporary objects +to hold the value of that parameter as specified in \ref{class.temporary}, +\begin{itemize} +\item +if the contract assertion +is a precondition assertion +and the evaluation of the precondition assertion +is sequenced before the initialization of the parameter object, +$E$ refers to the most recently initialized such temporary object, and +\item +if the contract assertion +is a postcondition assertion, +it is unspecified whether $E$ refers to +one of the temporary objects or the parameter object; +the choice is consistent within a single evaluation of a postcondition assertion. +\end{itemize} + +\pnum +If an \grammarterm{id-expression} $E$ +names a result binding +in a postcondition assertion +and the implementation introduces any temporary objects +to hold the result object as specified in \ref{class.temporary}, +and the postcondition assertion +is sequenced before the initialization of the result object\iref{expr.call}, +$E$ refers to the most recently initialized such temporary object. + + \begin{example} \begin{codeblock} void f() { @@ -1551,30 +1776,26 @@ \pnum An \defnadj{implicitly movable}{entity} is -a variable of automatic storage duration +a variable with automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. -In the following contexts, -an \grammarterm{id-expression} is \defn{move-eligible}: +An \grammarterm{id-expression} is \defn{move-eligible} if \begin{itemize} \item -If the \grammarterm{id-expression} (possibly parenthesized) -is the operand of a \tcode{return}\iref{stmt.return} or -\keyword{co_return}\iref{stmt.return.coroutine} statement, -and 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 \grammarterm{id-expression} (possibly parenthesized) -is the operand of a \grammarterm{throw-expression}\iref{expr.throw}, -and names an implicitly movable entity -that belongs to a scope that does not contain the \grammarterm{compound-statement} -of the innermost -\grammarterm{lambda-expression}, -\grammarterm{try-block}, or -\grammarterm{function-try-block} (if any) -whose \grammarterm{compound-statement} or \grammarterm{ctor-initializer} -contains the \grammarterm{throw-expression}. +it names an implicitly movable entity, +\item +it is the (possibly parenthesized) +operand of a \tcode{return}\iref{stmt.return} or +\keyword{co_return}\iref{stmt.return.coroutine} statement or +of a \grammarterm{throw-expression}\iref{expr.throw}, and +\item +each intervening scope between +the declaration of the entity and +the innermost enclosing scope of the \grammarterm{id-expression} +is a block scope and, +for a \grammarterm{throw-expression}, +is not the block scope of +a \grammarterm{try-block} or \grammarterm{function-try-block}. \end{itemize} \rSec3[expr.prim.id.qual]{Qualified names} @@ -1595,7 +1816,7 @@ \terminal{::}\br type-name \terminal{::}\br namespace-name \terminal{::}\br - decltype-specifier \terminal{::}\br + computed-type-specifier \terminal{::}\br nested-name-specifier identifier \terminal{::}\br nested-name-specifier \opt{\keyword{template}} simple-template-id \terminal{::} \end{bnf} @@ -1625,7 +1846,7 @@ a declarative \grammarterm{nested-name-specifier}. \end{itemize} A declarative \grammarterm{nested-name-specifier} -shall not have a \grammarterm{decltype-specifier}. +shall not have a \grammarterm{computed-type-specifier}. A declaration that uses a declarative \grammarterm{nested-name-specifier} shall be a friend declaration or inhabit a scope that contains the entity being redeclared or specialized. @@ -1633,8 +1854,8 @@ \pnum The \grammarterm{nested-name-specifier} \tcode{::} nominates the global namespace. -A \grammarterm{nested-name-specifier} with a \grammarterm{decltype-specifier} -nominates the type denoted by the \grammarterm{decltype-specifier}, +A \grammarterm{nested-name-specifier} with a \grammarterm{computed-type-specifier} +nominates the type denoted by the \grammarterm{computed-type-specifier}, which shall be a class or enumeration type. If a \grammarterm{nested-name-specifier} $N$ is declarative and @@ -1666,14 +1887,39 @@ \pnum A \grammarterm{qualified-id} shall not be of the form \grammarterm{nested-name-specifier} \opt{\keyword{template}} \tcode{\~} -\grammarterm{decltype-specifier} +\grammarterm{computed-type-specifier} nor of the form -\grammarterm{decltype-specifier} \tcode{::} \tcode{\~} \grammarterm{type-name}. +\grammarterm{computed-type-specifier} \tcode{::} \tcode{\~} \grammarterm{type-name}. \pnum The result of a \grammarterm{qualified-id} $Q$ is the entity it denotes\iref{basic.lookup.qual}. -The type of the expression is the type of the result. + +\pnum +If $Q$ appears +in the predicate of a contract assertion $C$\iref{basic.contract} +and the entity is +\begin{itemize} +\item +a variable +declared outside of $C$ +of object type \tcode{T}, +\item +a variable +declared outside of $C$ +of type ``reference to \tcode{T}'', or +\item +a structured binding of type \tcode{T} +whose corresponding variable +is declared outside of $C$, +\end{itemize} +then the type of the expression is \keyword{const}~\tcode{T}. + + +\pnum +Otherwise, the type of the expression is the type of the result. + +\pnum The result is an lvalue if the member is \begin{itemize} \item @@ -1690,6 +1936,32 @@ \end{itemize} and a prvalue otherwise. +\rSec3[expr.prim.pack.index]{Pack indexing expression} + +\begin{bnf} +\nontermdef{pack-index-expression}\br + id-expression \terminal{...} \terminal{[} constant-expression \terminal{]} +\end{bnf} + +\pnum +The \grammarterm{id-expression} $P$ in a \grammarterm{pack-index-expression} +shall be an \grammarterm{identifier} that denotes a pack. + +\pnum +The \grammarterm{constant-expression} shall be +a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +whose value $V$, termed the index, +is such that $0 \le V < \tcode{sizeof...($P$)}$. + +\pnum +A \grammarterm{pack-index-expression} is a pack expansion\iref{temp.variadic}. + +\pnum +\begin{note} +A \grammarterm{pack-index-expression} denotes +the $V^\text{th}$ element of the pack. +\end{note} + \rSec3[expr.prim.id.dtor]{Destruction} \pnum @@ -1747,10 +2019,11 @@ \begin{bnf} \nontermdef{lambda-declarator}\br lambda-specifier-seq \opt{noexcept-specifier} \opt{attribute-specifier-seq} \opt{trailing-return-type}\br - noexcept-specifier \opt{attribute-specifier-seq} \opt{trailing-return-type}\br - \opt{trailing-return-type}\br + \bnfindent \opt{function-contract-specifier-seq}\br + noexcept-specifier \opt{attribute-specifier-seq} \opt{trailing-return-type} \opt{function-contract-specifier-seq}\br + \opt{trailing-return-type} \opt{function-contract-specifier-seq}\br \terminal{(} parameter-declaration-clause \terminal{)} \opt{lambda-specifier-seq} \opt{noexcept-specifier} \opt{attribute-specifier-seq}\br - \bnfindent \opt{trailing-return-type} \opt{requires-clause} + \bnfindent \opt{trailing-return-type} \opt{requires-clause} \opt{function-contract-specifier-seq} \end{bnf} \begin{bnf} @@ -1763,8 +2036,7 @@ \begin{bnf} \nontermdef{lambda-specifier-seq}\br - lambda-specifier\br - lambda-specifier lambda-specifier-seq + lambda-specifier \opt{lambda-specifier-seq} \end{bnf} \pnum @@ -1851,8 +2123,9 @@ 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 +auto x = [](int i, auto a) { return i; }; // OK, a generic lambda +auto y = [](this auto self, int i) { return i; }; // OK, a generic lambda +auto z = [](int i) { return i; }; // OK, a generic lambda \end{codeblock} \end{example} @@ -1876,16 +2149,17 @@ \end{note} \pnum -The closure type is not an aggregate type\iref{dcl.init.aggr} and -not a structural type\iref{term.structural.type}. +The closure type is not an aggregate type\iref{dcl.init.aggr}; +it is a structural type\iref{term.structural.type} if and only if +the lambda has no \grammarterm{lambda-capture}. An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing: \begin{itemize} \item the size and/or alignment of the closure type, - -\item whether the closure type is trivially copyable\iref{class.prop}, or - +\item whether the closure type is trivially copyable\iref{class.prop}, +\item whether the closure type is trivially relocatable\iref{class.prop}, +\item whether the closure type is replaceable\iref{class.prop}, or \item whether the closure type is a standard-layout class\iref{class.prop}. \end{itemize} @@ -1948,7 +2222,7 @@ \item the closure type, \item -a class type derived from the closure type, or +a class type publicly and unambiguously derived from the closure type, or \item a reference to a possibly cv-qualified such type. \end{itemize} @@ -1980,8 +2254,9 @@ followed by \keyword{mutable} and the \grammarterm{lambda-declarator} does not contain an explicit object parameter. -It is neither virtual nor declared \tcode{volatile}. Any -\grammarterm{noexcept-specifier} specified on a \grammarterm{lambda-expression} +It is neither virtual nor declared \tcode{volatile}. +Any \grammarterm{noexcept-specifier} or \grammarterm{function-contract-specifier}\iref{dcl.contract.func} +specified on a \grammarterm{lambda-expression} applies to the corresponding function call operator or operator template. An \grammarterm{attribute-specifier-seq} in a \grammarterm{lambda-declarator} appertains to the type of the corresponding function call operator or operator template. @@ -2060,9 +2335,55 @@ \end{example} \end{note} +\pnum +If all potential references +to a local entity implicitly captured by a \grammarterm{lambda-expression} $L$ +occur within the function contract assertions\iref{dcl.contract.func} +of the call operator or operator template of $L$ +or within \grammarterm{assertion-statement}s\iref{stmt.contract.assert} +within the body of $L$, +the program is ill-formed. +\begin{note} +Adding a contract assertion to an existing \Cpp{} program cannot +cause additional captures. +\end{note} +\begin{example} +\begin{codeblock} +static int i = 0; + +void test() { + auto f1 = [=] pre(i > 0) {}; // OK, no local entities are captured. + + int i = 1; + auto f2 = [=] pre(i > 0) {}; // error: cannot implicitly capture \tcode{i} here + auto f3 = [i] pre(i > 0) {}; // OK, \tcode{i} is captured explicitly. + + auto f4 = [=] { + contract_assert(i > 0); // error: cannot implicitly capture \tcode{i} here + }; + + auto f5 = [=] { + contract_assert(i > 0); // OK, \tcode{i} is referenced elsewhere. + (void)i; + }; + + auto f6 = [=] pre( // \#1 + []{ + bool x = true; + return [=]{ return x; }(); // OK, \#1 captures nothing. + }()) {}; + + bool y = true; + auto f7 = [=] pre([=]{ return y; }()); // error: outer capture of \tcode{y} is invalid. +} +\end{codeblock} +\end{example} + + \pnum The closure type for a non-generic \grammarterm{lambda-expression} with no \grammarterm{lambda-capture} +and no explicit object parameter\iref{dcl.fct} whose constraints (if any) are satisfied has a conversion function to pointer to function with \Cpp{} language linkage\iref{dcl.link} having @@ -2072,9 +2393,9 @@ has a non-throwing exception specification. If the function call operator is a static member function, then the value returned by this conversion function is -the address of the function call operator. +a pointer to the function call operator. Otherwise, the value returned by this conversion function -is the address of a function \tcode{F} that, when invoked, +is a pointer to a function \tcode{F} that, when invoked, has the same effect as invoking the closure type's function call operator on a default-constructed instance of the closure type. \tcode{F} is a constexpr function @@ -2083,7 +2404,9 @@ if the function call operator is an immediate function. \pnum -For a generic lambda with no \grammarterm{lambda-capture}, the closure type has a +For a generic lambda with no \grammarterm{lambda-capture} +and no explicit object parameter\iref{dcl.fct}, +the closure type has a conversion function template to pointer to function. The conversion function template has the same invented template parameter list, and the pointer to function has the same @@ -2147,10 +2470,10 @@ If the function call operator template is a static member function template, then the value returned by any given specialization of this conversion function template is -the address of the corresponding function call operator template specialization. +a pointer to the corresponding function call operator template specialization. Otherwise, the value returned by any given specialization of this conversion function -template is the address of a function \tcode{F} that, when invoked, has the same +template is a pointer to a function \tcode{F} that, when invoked, has the same effect as invoking the generic lambda's corresponding function call operator template specialization on a default-constructed instance of the closure type. \tcode{F} is a constexpr function @@ -2159,7 +2482,7 @@ if the function call operator template specialization is an immediate function. \begin{note} This will result in the implicit instantiation of the generic lambda's body. -The instantiated generic lambda's return type and parameter types are required to match +The instantiated generic lambda's return type and parameter types need to match the return type and parameter types of the pointer to function. \end{note} \begin{example} @@ -2276,7 +2599,7 @@ \pnum The body of a \grammarterm{lambda-expression} may refer to local entities -of enclosing block scopes by capturing those entities, as described +of enclosing scopes by capturing those entities, as described below. \pnum @@ -2292,7 +2615,7 @@ or ``\tcode{* \keyword{this}}''. \begin{note} The form \tcode{[\&,\keyword{this}]} is redundant but accepted -for compatibility with ISO \CppXIV{}. +for compatibility with \CppXIV{}. \end{note} Ignoring appearances in \grammarterm{initializer}{s} of \grammarterm{init-capture}{s}, an identifier or @@ -2317,10 +2640,19 @@ A \grammarterm{lambda-expression} shall not have a \grammarterm{capture-default} or \grammarterm{simple-capture} in its \grammarterm{lambda-introducer} -unless its innermost enclosing scope is a block scope\iref{basic.scope.block} -or it appears within a default member initializer +unless +\begin{itemize} +\item +its innermost enclosing scope is a block scope\iref{basic.scope.block}, +\item +it appears within a default member initializer and its innermost enclosing scope is -the corresponding class scope\iref{basic.scope.class}. +the corresponding class scope\iref{basic.scope.class}, or +\item +it appears within a contract assertion +and its innermost enclosing scope +is the corresponding contract-assertion scope\iref{basic.scope.contract}. +\end{itemize} \pnum The \grammarterm{identifier} in a \grammarterm{simple-capture} @@ -2558,8 +2890,8 @@ \item it is explicitly captured with a capture that is not of the form \keyword{this}, -\tcode{\&} \grammarterm{identifier}, or -\tcode{\&} \grammarterm{identifier} \grammarterm{initializer}. +\tcode{\&} \grammarterm{identifier} \opt{\tcode{...}}, or +\tcode{\&} \opt{\tcode{...}} \grammarterm{identifier} \grammarterm{initializer}. \end{itemize} For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of @@ -2589,7 +2921,7 @@ void g() { const int N = 10; [=] { - int arr[N]; // OK, not an odr-use, refers to automatic variable + int arr[N]; // OK, not an odr-use, refers to variable with automatic storage duration f(&N); // OK, causes \tcode{N} to be captured; \tcode{\&N} points to // the corresponding member of the closure type }; @@ -2777,6 +3109,9 @@ } \end{codeblock} \end{example} + +\pnum +A fold expression is a pack expansion. \indextext{expression!fold|)}% \rSec2[expr.prim.req]{Requires expressions} @@ -2801,15 +3136,14 @@ \end{bnf} \begin{bnf} -\microtypesetup{protrusion=false}\obeyspaces +\microtypesetup{protrusion=false} \nontermdef{requirement-body}\br \terminal{\{} requirement-seq \terminal{\}} \end{bnf} \begin{bnf} \nontermdef{requirement-seq}\br - requirement\br - requirement requirement-seq + requirement \opt{requirement-seq} \end{bnf} \begin{bnf} @@ -2823,8 +3157,6 @@ \pnum A \grammarterm{requires-expression} is a prvalue of type \tcode{bool} whose value is described below. -Expressions appearing within a \grammarterm{requirement-body} -are unevaluated operands\iref{term.unevaluated.operand}. \pnum \begin{example} @@ -2852,9 +3184,11 @@ \pnum A \grammarterm{requires-expression} may introduce local parameters using a -\grammarterm{parameter-declaration-clause}\iref{dcl.fct}. +\grammarterm{parameter-declaration-clause}. A local parameter of a \grammarterm{requires-expression} shall not have a default argument. +The type of such a parameter is determined as specified for +a function parameter in~\ref{dcl.fct}. These parameters have no linkage, storage, or lifetime; they are only used as notation for the purpose of defining \grammarterm{requirement}s. The \grammarterm{parameter-declaration-clause} of a @@ -2866,13 +3200,19 @@ concept C = requires(T t, ...) { // error: terminates with an ellipsis t; }; +template +concept C2 = requires(T p[2]) { + (decltype(p))nullptr; // OK, \tcode{p} has type ``pointer to \tcode{T}'' +}; \end{codeblock} \end{example} \pnum The substitution of template arguments into a \grammarterm{requires-expression} -may result in the formation of invalid types or expressions in its -\grammarterm{requirement}s or the violation of the semantic constraints of those \grammarterm{requirement}s. +can result in +the formation of invalid types or expressions in the immediate context of +its \grammarterm{requirement}s\iref{temp.deduct.general} or +the violation of the semantic constraints of those \grammarterm{requirement}s. In such cases, the \grammarterm{requires-expression} evaluates to \keyword{false}; it does not cause the program to be ill-formed. The substitution and semantic constraint checking @@ -2908,10 +3248,10 @@ \pnum A \grammarterm{simple-requirement} asserts the validity of an \grammarterm{expression}. +The \grammarterm{expression} is an unevaluated operand. \begin{note} The enclosing \grammarterm{requires-expression} will evaluate to \keyword{false} if substitution of template arguments into the \grammarterm{expression} fails. -The \grammarterm{expression} is an unevaluated operand\iref{term.unevaluated.operand}. \end{note} \begin{example} \begin{codeblock} @@ -2940,6 +3280,8 @@ \pnum A \grammarterm{type-requirement} asserts the validity of a type. +The component names of a \grammarterm{type-requirement} are those of its +\grammarterm{nested-name-specifier} (if any) and \grammarterm{type-name}. \begin{note} The enclosing \grammarterm{requires-expression} will evaluate to \keyword{false} if substitution of template arguments fails. @@ -2977,7 +3319,9 @@ \pnum A \grammarterm{compound-requirement} asserts properties -of the \grammarterm{expression} $E$. Substitution +of the \grammarterm{expression} $E$. +The \grammarterm{expression} is an unevaluated operand. +Substitution of template arguments (if any) and verification of semantic properties proceed in the following order: @@ -3142,12 +3486,12 @@ a possibly empty, comma-separated list of \grammarterm{initializer-clause}s that constitute the arguments to the subscript operator. The \grammarterm{postfix-expression} and -the initialization of the object parameter of -any applicable subscript operator function is sequenced before +the initialization of the object parameter\iref{dcl.fct} of +any applicable subscript operator function\iref{over.sub} is sequenced before each expression in the \grammarterm{expression-list} and also before -any default argument. +any default argument\iref{dcl.fct.default}. The initialization of a non-object parameter of -a subscript operator function \tcode{S}\iref{over.sub}, +a subscript operator function \tcode{S}, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other non-object parameter of \tcode{S}. @@ -3243,14 +3587,20 @@ of the class member access\iref{expr.ref,basic.life}. \pnum +A type $\tcode{T}_\text{call}$ is +\defn{call-compatible} with a function type $\tcode{T}_\text{func}$ +if $\tcode{T}_\text{call}$ is the same type as $\tcode{T}_\text{func}$ or +if the type ``pointer to $\tcode{T}_\text{func}$'' can be +converted to type ``pointer to $\tcode{T}_\text{call}$'' +via a function pointer conversion\iref{conv.fctptr}. Calling a function through an -expression whose function type \tcode{E} is different -from the function type \tcode{F} of the called function's -definition results in undefined behavior -unless the type ``pointer to \tcode{F}'' can be converted -to the type ``pointer to \tcode{E}'' via a function pointer conversion\iref{conv.fctptr}. +expression whose function type +is not call-compatible with the +type of the called function's +definition results in undefined behavior. \begin{note} -The exception applies when the expression has the type of a +This requirement allows the case +when the expression has the type of a potentially-throwing function, but the called function has a non-throwing exception specification, and the function types are otherwise the same. @@ -3262,7 +3612,9 @@ \indextext{initialization!parameter}% When a function is called, each parameter\iref{dcl.fct} is initialized\iref{dcl.init,class.copy.ctor} with -its corresponding argument. +its corresponding argument, +and each precondition assertion of the function +is evaluated.\iref{dcl.contract.func} If the function is an explicit object member function and there is an implied object argument\iref{over.call.func}, the list of provided arguments is preceded by the implied object argument @@ -3276,9 +3628,11 @@ \end{codeblock} \end{example} If the function is an implicit object member -function, the \keyword{this} parameter of the function\iref{expr.prim.this} -is initialized with a pointer to the object of the call, converted -as if by an explicit type conversion\iref{expr.cast}. +function, +the object expression of the class member access shall be a glvalue and +the implicit object parameter of the function\iref{over.match.funcs} +is initialized with that glvalue, +converted as if by an explicit type conversion\iref{expr.cast}. \begin{note} There is no access or ambiguity checking on this conversion; the access checking and disambiguation are done as part of the (possibly implicit) @@ -3293,10 +3647,12 @@ a type. However, it prevents a passed-by-value parameter to have an incomplete or abstract class type. \end{note} -It is \impldef{whether the lifetime of a parameter ends when the callee -returns or at the end of the enclosing full-expression} whether the -lifetime of a parameter ends when the function in which it is defined -returns or at the end of the enclosing full-expression. +It is \impldef{whether a parameter is destroyed when the function +exits or at the end of the enclosing full-expression} +whether a parameter is destroyed +when the function in which it is defined exits\iref{stmt.return, except.ctor, expr.await} +or at the end of the enclosing full-expression; +parameters are always destroyed in the reverse order of their construction. The initialization and destruction of each parameter occurs within the context of the full-expression\iref{intro.execution} where the function call appears. @@ -3318,9 +3674,21 @@ The \grammarterm{postfix-expression} is sequenced before each \grammarterm{expression} in the \grammarterm{expression-list} and any default argument. -The initialization of a parameter, +The initialization of a parameter or, +if the implementation introduces any temporary objects +to hold the values of function parameters\iref{class.temporary}, +the initialization of those temporaries, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter. +These evaluations are +sequenced before +the evaluation of the precondition assertions of the function, +which are evaluated in sequence\iref{dcl.contract.func}. +For any temporaries +introduced to hold the values of function parameters, +the initialization of the parameter objects from those temporaries +is indeterminately sequenced with respect to +the evaluation of each precondition assertion. \begin{note} All side effects of argument evaluations are sequenced before the function is @@ -3366,6 +3734,18 @@ chosen function, the value returned from the final overrider is converted to the return type of the statically chosen function. +\pnum +When the called function exits normally\iref{stmt.return,expr.await}, +all postcondition assertions of the function +are evaluated in sequence\iref{dcl.contract.func}. +If the implementation introduces any temporary objects +to hold the result value as specified in \ref{class.temporary}, +the evaluation of each postcondition assertion +is indeterminately sequenced with respect to +the initialization of any of those temporaries or the result object. +These evaluations, in turn, are sequenced before +the destruction of any function parameters. + \pnum \begin{note} \indextext{type checking!argument}% @@ -3377,7 +3757,7 @@ A function can change the values of its non-const parameters, but these changes cannot affect the values of the arguments except where a parameter is of a reference type\iref{dcl.ref}; if the reference is to -a const-qualified type, \keyword{const_cast} is required to be used to +a const-qualified type, \keyword{const_cast} needs to be used to cast away the constness in order to modify the argument's value. Where a parameter is of \keyword{const} reference type a temporary object is introduced if @@ -3402,7 +3782,7 @@ \indextext{ellipsis!conversion sequence}% When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the -argument by invoking \tcode{va_arg}\iref{support.runtime}. +argument by invoking \libmacro{va_arg}\iref{support.runtime}. \begin{note} This paragraph does not apply to arguments passed to a function parameter pack. Function parameter packs are expanded during template instantiation\iref{temp.variadic}, @@ -3442,6 +3822,9 @@ if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise. +If it is a non-void prvalue, +the type of the function call expression shall be complete, +except as specified in \ref{dcl.type.decltype}. \rSec3[expr.type.conv]{Explicit type conversion (functional notation)} @@ -3468,6 +3851,44 @@ Otherwise, if the type contains a placeholder type, it is replaced by the type determined by placeholder type deduction\iref{dcl.type.auto.deduct}. +Let \tcode{T} denote the resulting type. +Then: + +\begin{itemize} +\item +If the initializer is a parenthesized single expression, +the type conversion expression is equivalent +to the corresponding cast +expression\iref{expr.cast}. + +\item +\indextext{type!incomplete}% +Otherwise, if \tcode{T} is \cv{}~\keyword{void}, +the initializer shall be \tcode{()} or \tcode{\{\}} +(after pack expansion, if any), and +the expression is a prvalue of type \keyword{void} +that performs no initialization. + +\item +Otherwise, if \tcode{T} is a reference type, +the expression has the same effect as +direct-initializing an invented variable \tcode{t} of type \tcode{T} from +the initializer and then +using \tcode{t} as the result of the expression; +the result is an lvalue if +\tcode{T} is an lvalue reference type or +an rvalue reference to function type and +an xvalue otherwise. + +\item +Otherwise, +the expression is a prvalue of type \tcode{T} +whose result object is direct-initialized\iref{dcl.init} +with the initializer. +\end{itemize} + +If the initializer is a parenthesized optional \grammarterm{expression-list}, +\tcode{T} shall not be an array type. \begin{example} \begin{codeblock} struct A {}; @@ -3482,24 +3903,6 @@ \end{codeblock} \end{example} -\pnum -If the initializer is a parenthesized single expression, -the type conversion expression is equivalent -to the corresponding cast -expression\iref{expr.cast}. -\indextext{type!incomplete}% -Otherwise, if the type is \cv{}~\keyword{void} -and the initializer is \tcode{()} or \tcode{\{\}} -(after pack expansion, if any), -the expression is a prvalue of type \keyword{void} -that performs no initialization. -Otherwise, -the expression is a prvalue of the specified type -whose result object is direct-initialized\iref{dcl.init} -with the initializer. -If the initializer is a parenthesized optional \grammarterm{expression-list}, -the specified type shall not be an array type. - \rSec3[expr.ref]{Class member access} \pnum @@ -3516,18 +3919,7 @@ A postfix expression followed by a dot \tcode{.} or an arrow \tcode{->}, optionally followed by the keyword \keyword{template}, and then followed by an -\grammarterm{id-expression}, is a postfix expression. The postfix -expression before the dot or arrow is evaluated; -\begin{footnote} -If the class member -access expression is evaluated, the subexpression evaluation happens even if the -result is unnecessary to determine -the value of the entire postfix expression, for example if the -\grammarterm{id-expression} denotes a static member. -\end{footnote} -the result of that evaluation, together with the -\grammarterm{id-expression}, determines the result of the entire postfix -expression. +\grammarterm{id-expression}, is a postfix expression. \begin{note} If the keyword \keyword{template} is used, the following unqualified name @@ -3538,8 +3930,12 @@ \pnum \indextext{type!incomplete}% -For the first option (dot) the first expression shall be a glvalue. -For the second option (arrow) the first expression +For the first option (dot), +if the \grammarterm{id-expression} names a static member or an enumerator, +the first expression is a discarded-value expression\iref{expr.context}; +if the \grammarterm{id-expression} names a non-static data member, +the first expression shall be a glvalue. +For the second option (arrow), the first expression shall be a prvalue having pointer type. The expression \tcode{E1->E2} is converted to the equivalent form \tcode{(*(E1)).E2}; the remainder of @@ -3549,6 +3945,19 @@ \tcode{(*(E1))} is an lvalue. \end{footnote} +\pnum +The postfix expression before the dot is evaluated; +\begin{footnote} +If the class member +access expression is evaluated, the subexpression evaluation happens even if the +result is unnecessary to determine +the value of the entire postfix expression, for example if the +\grammarterm{id-expression} denotes a static member. +\end{footnote} +the result of that evaluation, +together with the \grammarterm{id-expression}, +determines the result of the entire postfix expression. + \pnum Abbreviating \grammarterm{postfix-expression}\tcode{.}\grammarterm{id-expression} @@ -3617,6 +4026,8 @@ ``\cvqual{cq12} \cvqual{vq12} \tcode{T}''. \item If \tcode{E2} is an overload set, +the expression shall be the (possibly-parenthesized) left-hand operand of +a member function call\iref{expr.call}, and function overload resolution\iref{over.match} is used to select the function to which \tcode{E2} refers. The type of \tcode{E1.E2} is the type of \tcode{E2} @@ -3627,8 +4038,7 @@ \tcode{E1.E2} is an lvalue. \item Otherwise (when \tcode{E2} refers to a non-static member function), -\tcode{E1.E2} is a prvalue. The expression can be used only as the -left-hand operand of a member function call\iref{class.mfct}. +\tcode{E1.E2} is a prvalue. \begin{note} Any redundant set of parentheses surrounding the expression is ignored\iref{expr.prim.paren}. @@ -3678,8 +4088,8 @@ \indextext{operator!increment}% \indextext{\idxcode{++}|see{operator, increment}}% \indextext{postfix \tcode{++}}% -The value of a postfix \tcode{++} expression is the value of its -operand. +The value of a postfix \tcode{++} expression is the value obtained by +applying the lvalue-to-rvalue conversion\iref{conv.lval} to its operand. \begin{note} The value obtained is a copy of the original value. \end{note} @@ -3689,7 +4099,7 @@ An operand with volatile-qualified type is deprecated; see~\ref{depr.volatile.type}. The value of the operand object is modified\iref{defns.access} -by adding \tcode{1} to it. +as if it were the operand of the prefix \tcode{++} operator\iref{expr.pre.incr}. The \indextext{value computation}% value computation of the \tcode{++} expression is sequenced before the @@ -3704,11 +4114,6 @@ \end{note} The result is a prvalue. The type of the result is the cv-unqualified version of the type of the operand. -If the operand is a bit-field that cannot represent the incremented value, the -resulting value of the bit-field is -\impldefplain{value of bit-field that cannot represent!incremented value}. -See also~\ref{expr.add} -and~\ref{expr.ass}. \pnum \indextext{expression!decrement}% @@ -3784,6 +4189,22 @@ \pnum If \tcode{v} is a null pointer value, the result is a null pointer value. +\pnum +If \tcode{v} has type ``pointer to \cv{}~\tcode{U}'' and +\tcode{v} does not point to an object +whose type is similar\iref{conv.qual} to \tcode{U} and +that is +within its lifetime or +within its period of construction or destruction\iref{class.cdtor}, +the behavior is undefined. +If \tcode{v} is a glvalue of type \tcode{U} and +\tcode{v} does not refer to an object +whose type is similar to \tcode{U} and +that is +within its lifetime or +within its period of construction or destruction, +the behavior is undefined. + \pnum If \tcode{T} is ``pointer to \cv{} \keyword{void}'', then the result is a pointer to the most derived object pointed to by \tcode{v}. @@ -3799,7 +4220,8 @@ \item If, in the most derived object pointed (referred) to by \tcode{v}, \tcode{v} points (refers) to a public base class subobject of a \tcode{C} object, and if only one object of type \tcode{C} is derived -from the subobject pointed (referred) to by \tcode{v} the result points (refers) to that \tcode{C} object. +from the subobject pointed (referred) to by \tcode{v}, +the result points (refers) to that \tcode{C} object. \item Otherwise, if \tcode{v} points (refers) to a public base class subobject of the most derived object, and the type of the most @@ -3878,26 +4300,27 @@ a reference to (possibly cv-qualified) class type, that class shall be completely defined. +\pnum +If an \grammarterm{expression} operand of \keyword{typeid} is +a possibly-parenthesized \grammarterm{unary-expression} +whose \grammarterm{unary-operator} is \tcode{*} and +whose operand evaluates to a null pointer value\iref{basic.compound}, +the \keyword{typeid} expression throws an exception\iref{except.throw} +of a type that would match a handler of type +\indextext{\idxcode{bad_typeid}}% +\indexlibraryglobal{bad_typeid}% +\tcode{std::bad_typeid}\iref{bad.typeid}. +\begin{note} +In other contexts, evaluating such a \grammarterm{unary-expression} +results in undefined behavior\iref{expr.unary.op}. +\end{note} + \pnum When \keyword{typeid} is applied to a glvalue whose type is a polymorphic class type\iref{class.virtual}, the result refers to a \tcode{std::type_info} object representing the type of the most derived object\iref{intro.object} (that is, the dynamic type) to which the -glvalue refers. If the glvalue is obtained by applying the -unary \tcode{*} operator to a pointer -\begin{footnote} -If \tcode{p} is an expression of -pointer type, then \tcode{*p}, -\tcode{(*p)}, \tcode{*(p)}, \tcode{((*p))}, \tcode{*((p))}, and so on -all meet this requirement. -\end{footnote} -and the pointer is a null pointer value\iref{basic.compound}, the -\keyword{typeid} expression throws an exception\iref{except.throw} of -a type that would match a handler of type -\indextext{\idxcode{bad_typeid}}% -\indexlibraryglobal{bad_typeid}% -\tcode{std::bad_typeid} -exception\iref{bad.typeid}. +glvalue refers. \pnum When \keyword{typeid} is applied to an expression other than a glvalue of @@ -4012,7 +4435,22 @@ a program that necessitates such a cast is ill-formed. \pnum -An expression $E$ can be explicitly converted to a type \tcode{T} +Any expression can be explicitly converted to type \cv{}~\keyword{void}, +in which case the operand is a discarded-value expression\iref{expr.prop}. +\begin{note} +Such a \keyword{static_cast} has no result +as it is a prvalue of type \keyword{void}; see~\ref{basic.lval}. +\end{note} +\begin{note} +However, if the value is in a temporary +object\iref{class.temporary}, the destructor for that +object is +not executed until the usual time, and the value of the object is +preserved for the purpose of executing the destructor. +\end{note} + +\pnum +Otherwise, an expression $E$ can be explicitly converted to a type \tcode{T} if there is an implicit conversion sequence\iref{over.best.ics} from $E$ to \tcode{T}, if overload resolution for a direct-initialization\iref{dcl.init} @@ -4040,28 +4478,8 @@ \end{note} \pnum -Otherwise, the \keyword{static_cast} shall perform one of the conversions -listed below. No other conversion shall be performed explicitly using a -\keyword{static_cast}. - -\pnum -Any expression can be explicitly converted to type \cv{}~\keyword{void}, -in which case the operand is a discarded-value expression\iref{expr.prop}. -\begin{note} -Such a \keyword{static_cast} has no result -as it is a prvalue of type \keyword{void}; see~\ref{basic.lval}. -\end{note} -\begin{note} -However, if the value is in a temporary -object\iref{class.temporary}, the destructor for that -object is -not executed until the usual time, and the value of the object is -preserved for the purpose of executing the destructor. -\end{note} - - -\pnum -The inverse of any standard conversion sequence\iref{conv} not containing an +Otherwise, +the inverse of a standard conversion sequence\iref{conv} not containing an lvalue-to-rvalue\iref{conv.lval}, array-to-pointer\iref{conv.array}, function-to-pointer\iref{conv.func}, @@ -4191,7 +4609,7 @@ If the original pointer value represents the address \tcode{A} of a byte in memory and \tcode{A} does not satisfy the alignment requirement of \tcode{T}, -then the resulting pointer value is unspecified. +then the resulting pointer value\iref{basic.compound} is unspecified. Otherwise, if the original pointer value points to an object \placeholder{a}, and there is an object \placeholder{b} of type similar to \tcode{T} that is pointer-interconvertible\iref{basic.compound} with \placeholder{a}, @@ -4205,6 +4623,9 @@ \end{codeblock} \end{example} +\pnum +No other conversion can be performed using \keyword{static_cast}. + \rSec3[expr.reinterpret.cast]{Reinterpret cast} \pnum @@ -4261,7 +4682,7 @@ A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type -will have its original value; +will have its original value\iref{basic.compound}; \indextext{conversion!implementation-defined pointer integer}% mappings between pointers and integers are otherwise \impldef{conversions between pointers and integers}. @@ -4283,9 +4704,6 @@ \tcode{T2}'' (where \tcode{T1} and \tcode{T2} are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. -\begin{note} -See also~\ref{conv.ptr} for more details of pointer conversions. -\end{note} \pnum An object pointer @@ -4360,22 +4778,25 @@ \indextext{cast!reinterpret!reference}% \indextext{cast!reference}% \indextext{type pun}% -A glvalue of type \tcode{T1}, -designating an object \placeholder{x}, -can be cast to the type ``reference to \tcode{T2}'' +If \tcode{v} is a glvalue of type \tcode{T1}, +designating an object or function \placeholder{x}, +it can be cast to the type ``reference to \tcode{T2}'' if an expression of type ``pointer to \tcode{T1}'' can be explicitly converted to the type ``pointer to \tcode{T2}'' using a \keyword{reinterpret_cast}. The result is that of \tcode{*reinterpret_cast(p)} where \tcode{p} is a pointer to \placeholder{x} of type ``pointer to \tcode{T1}''. -No temporary is created, no copy is made, and +\begin{note} +No temporary is materialized\iref{conv.rval} or created, +no copy is made, and no constructors\iref{class.ctor} or conversion functions\iref{class.conv} are called. \begin{footnote} This is sometimes referred to as a type pun when the result refers to the same object as the source glvalue. \end{footnote} +\end{note} \rSec3[expr.const.cast]{Const cast} @@ -4389,7 +4810,10 @@ otherwise, the result is a prvalue and the lvalue-to-rvalue\iref{conv.lval}, array-to-pointer\iref{conv.array}, and function-to-pointer\iref{conv.func} standard conversions are -performed on the expression \tcode{v}. Conversions that can be performed explicitly using +performed on the expression \tcode{v}. +The temporary materialization conversion\iref{conv.rval} is not +performed on \tcode{v}, other than as specified below. +Conversions that can be performed explicitly using \keyword{const_cast} are listed below. No other conversion shall be performed explicitly using \keyword{const_cast}. @@ -4400,23 +4824,16 @@ \end{note} \pnum -For two similar types \tcode{T1} and \tcode{T2}\iref{conv.qual}, -a prvalue of type \tcode{T1} may be explicitly +For two similar object pointer or pointer to data member types +\tcode{T1} and \tcode{T2}\iref{conv.qual}, +a prvalue of type \tcode{T1} can be explicitly converted to the type \tcode{T2} using a \keyword{const_cast} if, considering the qualification-decompositions of both types, each $P^1_i$ is the same as $P^2_i$ for all $i$. -The result of a \keyword{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} - -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} +If \tcode{v} is a null pointer or null member pointer, +the result is a null pointer or null member pointer, respectively. +Otherwise, the result points to or past the end of the same object, or +points to the same member, respectively, as \tcode{v}. \pnum For two object types \tcode{T1} and \tcode{T2}, if a pointer to \tcode{T1} can @@ -4429,20 +4846,22 @@ \item a glvalue of type \tcode{T1} can be explicitly converted to an xvalue of type \tcode{T2} using the cast \tcode{\keyword{const_cast}}; and -\item if \tcode{T1} is a class type, a prvalue of type \tcode{T1} can be +\item if \tcode{T1} is a class or array type, +a prvalue of type \tcode{T1} can be explicitly converted to an xvalue of type \tcode{T2} using the cast \tcode{\keyword{const_cast}}. +The temporary materialization conversion is performed on \tcode{v}. \end{itemize} -The result of a reference \keyword{const_cast} refers -to the original object if the operand is a glvalue and -to the result of applying the temporary materialization conversion\iref{conv.rval} otherwise. +The result refers to the same object as the (possibly converted) operand. +\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} -\pnum -A null pointer value\iref{basic.compound} is converted to the null pointer -value of the destination type. The null member pointer -value\iref{conv.mem} is converted to the null member pointer value of -the destination type. +auto &&r2 = const_cast(CA{}); // OK, temporary materialization conversion is performed +\end{codeblock} +\end{example} \pnum \begin{note} @@ -4555,8 +4974,10 @@ \indextext{dereferencing|see{indirection}}% Its operand shall be a prvalue of type ``pointer to \tcode{T}'', where \tcode{T} is an object or function type. -The operator yields an lvalue of type \tcode{T} -denoting the object or function to which the operand points. +The operator yields an lvalue of type \tcode{T}. +If the operand points to an object or function, +the result denotes that object or function; +otherwise, the behavior is undefined except as specified in \ref{expr.typeid}. \begin{note} \indextext{type!incomplete}% Indirection through a pointer to an incomplete type (other than @@ -4573,7 +4994,6 @@ \indextext{expression!pointer-to-member constant}% The operand of the unary \tcode{\&} operator shall be an lvalue of some type \tcode{T}. -The result is a prvalue. \begin{itemize} \item If the operand is a \grammarterm{qualified-id} naming a non-static or variant member \tcode{m} @@ -4689,14 +5109,14 @@ \end{note} There is an ambiguity in the grammar when \tcode{\~{}} is followed by -a \grammarterm{type-name} or \grammarterm{decltype-specifier}. +a \grammarterm{type-name} or \grammarterm{computed-type-specifier}. The ambiguity is resolved by treating \tcode{\~{}} as the operator rather than as the start of an \grammarterm{unqualified-id} naming a destructor. \begin{note} Because the grammar does not permit an operator to follow the \tcode{.}, \tcode{->}, or \tcode{::} tokens, a \tcode{\~{}} followed by -a \grammarterm{type-name} or \grammarterm{decltype-specifier} in a +a \grammarterm{type-name} or \grammarterm{computed-type-specifier} in a member access expression or \grammarterm{qualified-id} is unambiguously parsed as a destructor name. \end{note} @@ -4706,32 +5126,16 @@ \pnum \indextext{expression!increment}% \indextext{expression!decrement}% -The operand of prefix \tcode{++} \indextext{operator!increment}% +\indextext{operator!decrement}% \indextext{prefix \tcode{++}}% -is modified\iref{defns.access} by adding \tcode{1}. \indextext{prefix \tcode{--}}% -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. +The operand of prefix \tcode{++} or \tcode{--} +shall not be of type \cv{}~\tcode{bool}. An operand with 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}. -\indextext{operator!\idxcode{+=}}% -\begin{note} -See the discussions of addition\iref{expr.add} and assignment -operators\iref{expr.ass} for information on conversions. -\end{note} - -\pnum -The operand of prefix -\indextext{operator!decrement}% -\tcode{--} is modified\iref{defns.access} by subtracting \tcode{1}. -The requirements on the operand of prefix -\tcode{--} and the properties of its result are otherwise the same as -those of prefix \tcode{++}. +The expression \tcode{++x} is otherwise equivalent to \tcode{x+=1} and +the expression \tcode{--x} is otherwise equivalent to \tcode{x-=1}\iref{expr.assign}. \begin{note} For postfix increment and decrement, see~\ref{expr.post.incr}. \end{note} @@ -4744,6 +5148,8 @@ The \keyword{co_await} expression is used to suspend evaluation of a coroutine\iref{dcl.fct.def.coroutine} while awaiting completion of the computation represented by the operand expression. +Suspending the evaluation of a coroutine +transfers control to its caller or resumer. \begin{bnf} \nontermdef{await-expression}\br @@ -4751,9 +5157,11 @@ \end{bnf} \pnum -An \grammarterm{await-expression} shall appear only in a potentially-evaluated +An \grammarterm{await-expression} shall appear only as a potentially-evaluated expression within the \grammarterm{compound-statement} of a -\grammarterm{function-body} outside of a \grammarterm{handler}\iref{except.pre}. +\grammarterm{function-body} or \grammarterm{lambda-expression}, +in either case +outside of a \grammarterm{handler}\iref{except.pre}. In a \grammarterm{declaration-statement} or in the \grammarterm{simple-declaration} (if any) of an \grammarterm{init-statement}, an \grammarterm{await-expression} @@ -4763,6 +5171,9 @@ default argument\iref{dcl.fct.default}. An \grammarterm{await-expression} shall not appear in the initializer of a block variable with static or thread storage duration. +An \grammarterm{await-expression} shall not be +a potentially-evaluated subexpression +of the predicate of a contract assertion\iref{basic.contract}. A context within a function where an \grammarterm{await-expression} can appear is called a \term{suspension context} of the function. @@ -5017,7 +5428,7 @@ \begin{note} A \keyword{sizeof} expression is an integral constant expression\iref{expr.const}. -The type \tcode{std::size_t} is defined in the standard header +The \grammarterm{typedef-name} \tcode{std::size_t} is declared in the standard header \libheader{cstddef}\iref{cstddef.syn,support.types.layout}. \end{note} @@ -5036,7 +5447,7 @@ \begin{note} An \keyword{alignof} expression is an integral constant expression\iref{expr.const}. -The type \tcode{std::size_t} is defined in the standard header +The \grammarterm{typedef-name} \tcode{std::size_t} is declared in the standard header \libheader{cstddef}\iref{cstddef.syn,support.types.layout}. \end{note} @@ -5048,31 +5459,29 @@ \rSec3[expr.unary.noexcept]{\tcode{noexcept} operator} -\pnum \indextext{\idxcode{noexcept}}% \indextext{expression!\idxcode{noexcept}}% -The \keyword{noexcept} operator determines whether the evaluation of its operand, -which is an unevaluated operand\iref{term.unevaluated.operand}, can throw an -exception\iref{except.throw}. \begin{bnf} \nontermdef{noexcept-expression}\br \keyword{noexcept} \terminal{(} expression \terminal{)} \end{bnf} +\pnum +The operand of the \keyword{noexcept} operator +is an unevaluated operand\iref{term.unevaluated.operand}. +If the operand is a prvalue, +the temporary materialization conversion\iref{conv.rval} is applied. + \pnum The result of the \keyword{noexcept} operator is a prvalue of type \keyword{bool}. +The result is \tcode{false} if +the full-expression of the operand is potentially-throwing\iref{except.spec}, and +\tcode{true} otherwise. \begin{note} A \grammarterm{noexcept-expression} is an integral constant expression\iref{expr.const}. \end{note} - -\pnum -If the operand is a prvalue, -the temporary materialization conversion\iref{conv.rval} is applied. -The result of the \keyword{noexcept} operator is \keyword{true} -unless the full-expression of the operand -is potentially-throwing\iref{except.spec}. \indextext{expression!unary|)} \rSec3[expr.new]{New} @@ -5139,7 +5548,9 @@ \end{bnf} \pnum -If a placeholder type\iref{dcl.spec.auto} appears in the +If a placeholder type\iref{dcl.spec.auto} or +a placeholder for a deduced class type\iref{dcl.type.class.deduct} +appears in the \grammarterm{type-specifier-seq} of a \grammarterm{new-type-id} or \grammarterm{type-id} of a \grammarterm{new-expression}, the allocated type is deduced as follows: @@ -5221,6 +5632,15 @@ \grammarterm{expression} of a \grammarterm{noptr-new-declarator}), but \tcode{new float[5][n]} is ill-formed (because \tcode{n} is not a constant expression). +Furthermore, +\tcode{new float[0]} is well-formed +(because \tcode{0} is the \grammarterm{expression} +of a \grammarterm{noptr-new-declarator}, +where a value of zero results in the allocation of an array with no elements), +but \tcode{new float[n][0]} is ill-formed +(because \tcode{0} is the \grammarterm{constant-expression} +of a \grammarterm{noptr-new-declarator}, +where only values greater than zero are allowed). \end{example} \pnum @@ -5237,7 +5657,7 @@ If the \grammarterm{expression} in a \grammarterm{noptr-new-declarator} is present, it is implicitly converted to \tcode{std::size_t}. \indextext{function!allocation}% -The \grammarterm{expression} is erroneous if: +The value of the \grammarterm{expression} is invalid if \begin{itemize} \item the expression is of non-class type and its value before converting to @@ -5265,7 +5685,7 @@ number of elements to initialize. \end{itemize} -If the \grammarterm{expression} is erroneous after converting to \tcode{std::size_t}: +If the value of the \grammarterm{expression} is invalid after converting to \tcode{std::size_t}: \begin{itemize} \item if the \grammarterm{expression} is a potentially-evaluated core constant expression, @@ -5287,6 +5707,21 @@ When the value of the \grammarterm{expression} is zero, the allocation function is called to allocate an array with no elements. +\pnum +If the allocated type is an array, +the \grammarterm{new-initializer} is a \grammarterm{braced-init-list}, and +the \grammarterm{expression} +is potentially-evaluated and not a core constant expression, +the semantic constraints of copy-initializing a hypothetical element of +the array from an empty initializer list +are checked\iref{dcl.init.list}. +\begin{note} +The array can contain more elements than there are +elements in the \grammarterm{braced-init-list}, +requiring initialization of the remainder of the array elements from +an empty initializer list. +\end{note} + \pnum \indextext{storage duration!dynamic}% Objects created by a \grammarterm{new-expression} have dynamic storage @@ -5331,7 +5766,7 @@ and the deallocation function's name is \tcode{\keyword{operator} \keyword{delete}[]}. \begin{note} -An implementation is required to provide default definitions for the global +An implementation is expected to provide default definitions for the global allocation functions\iref{basic.stc.dynamic,new.delete.single,new.delete.array}. A \Cpp{} program can provide alternative definitions of @@ -5362,12 +5797,7 @@ \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} +a call to a replaceable allocation function is always omitted\iref{expr.const}. \pnum The implementation may @@ -5585,10 +6015,6 @@ \grammarterm{new-expression}. \pnum -If the \grammarterm{new-expression} creates an object or an array of -objects of class type, access and ambiguity control are done for the -allocation function, the deallocation function\iref{basic.stc.dynamic.deallocation}, and -the constructor\iref{class.ctor} selected for the initialization (if any). If the \grammarterm{new-expression} creates an array of objects of class type, the destructor is potentially invoked\iref{class.dtor}. @@ -5638,6 +6064,9 @@ ill-formed. For a non-placement allocation function, the normal deallocation function lookup is used to find the matching deallocation function\iref{expr.delete}. +In any case, +the matching deallocation function (if any) shall be non-deleted and +accessible from the point where the \grammarterm{new-expression} appears. \begin{example} \begin{codeblock} struct S { @@ -5696,22 +6125,15 @@ If the operand is of class type, it is contextually implicitly converted\iref{conv} to a pointer to object -type. -\begin{footnote} -This implies that an object -cannot be deleted using a pointer of type -\tcode{\keyword{void}*} because \keyword{void} is not an object type. -\end{footnote} +type +and the converted operand is used in place of the original operand +for the remainder of this subclause. Otherwise, it shall be a prvalue of pointer to object type. The \grammarterm{delete-expression} has type \keyword{void}. \pnum \indextext{\idxcode{delete}!single-object}% -If the operand has a class type, the operand is converted to a pointer -type by calling the above-mentioned conversion function, and the -converted operand is used in place of the original operand for the -remainder of this subclause. In a single-object delete expression, the value of the operand of \keyword{delete} may be a null pointer value, a pointer value @@ -5755,15 +6177,10 @@ expression, if the dynamic type of the object to be deleted is not similar to its static type, the behavior is undefined. -\pnum -The \grammarterm{cast-expression} in a \grammarterm{delete-expression} shall -be evaluated exactly once. - \pnum \indextext{type!incomplete}% -If the object being deleted has incomplete class type at the point of -deletion and the complete class has a non-trivial destructor or a -deallocation function, the behavior is undefined. +If the object being deleted has incomplete class type at the point of deletion, +the program is ill-formed. \pnum \indextext{\idxcode{delete}!destructor and}% @@ -5771,9 +6188,12 @@ null pointer value and the selected deallocation function (see below) is not a destroying operator delete, -the \grammarterm{delete-expression} will invoke the +evaluating the \grammarterm{delete-expression} invokes the destructor (if any) for the object or the elements of the array being -deleted. In the case of an array, the elements will be destroyed in +deleted. +The destructor shall be accessible from the point where +the \grammarterm{delete-expression} appears. +In the case of an array, the elements are destroyed in order of decreasing address (that is, in reverse order of the completion of their constructor; see~\ref{class.base.init}). @@ -5854,8 +6274,7 @@ \end{note} \pnum -If more than one deallocation function is found, -the function to be called is selected as follows: +The deallocation function to be called is selected as follows: \begin{itemize} \item If any of the deallocation functions is a destroying operator delete, @@ -5884,6 +6303,10 @@ whether a deallocation function with a parameter of type \tcode{std::size_t} is selected. \end{itemize} +Unless the deallocation function is selected +at the point of definition of the dynamic type's virtual destructor, +the selected deallocation function shall be accessible +from the point where the \grammarterm{delete-expression} appears. \pnum For a single-object delete expression, @@ -5937,10 +6360,6 @@ the behavior is undefined\iref{new.delete.single,new.delete.array}. \end{note} -\pnum -Access and ambiguity control are done for both the deallocation function -and the destructor\iref{class.dtor,class.free}. - \rSec2[expr.cast]{Explicit type conversion (cast notation)}% \indextext{expression!cast|(} @@ -6006,8 +6425,9 @@ If a conversion can be interpreted in more than one of the ways listed above, the interpretation that appears first in the list is used, even if a cast resulting from that interpretation is ill-formed. If a -conversion can be interpreted in more than one way as a -\keyword{static_cast} followed by a \keyword{const_cast}, the conversion is +\keyword{static_cast} followed by a \keyword{const_cast} is used and +the conversion can be interpreted in more than one way as such, +the conversion is ill-formed. \begin{example} \begin{codeblock} @@ -6018,6 +6438,15 @@ A* foo( D* p ) { return (A*)( p ); // ill-formed \keyword{static_cast} interpretation } + +int*** ptr = 0; +auto t = (int const*const*const*)ptr; // OK, \keyword{const_cast} interpretation + +struct S { + operator const int*(); + operator volatile int*(); +}; +int *p = (int*)S(); // error: two possible interpretations using \keyword{static_cast} followed by \keyword{const_cast} \end{codeblock} \end{example} @@ -6032,7 +6461,7 @@ inheritance relationship between the two classes. \begin{note} For example, if the classes were defined later in the translation unit, -a multi-pass compiler would be permitted to interpret a cast between +a multi-pass compiler could validly interpret a cast between pointers to the classes as if the class types were complete at the point of the cast. \end{note} @@ -6248,7 +6677,7 @@ \begin{itemize} \item If \tcode{P} evaluates to a null pointer value and \tcode{J} evaluates to 0, the result is a null pointer value. -\item Otherwise, if \tcode{P} points to an array element $i$ +\item Otherwise, if \tcode{P} points to a (possibly-hypothetical) array element $i$ of an array object \tcode{x} with $n$ elements\iref{dcl.array}, \begin{footnote} As specified in \ref{basic.compound}, @@ -6280,7 +6709,7 @@ \indextext{comparison!undefined pointer}% When two pointer expressions \tcode{P} and \tcode{Q} are subtracted, the type of the result is an \impldef{type of \tcode{ptrdiff_t}} signed -integral type; this type shall be the same type that is defined as +integral type; this type shall be the same type that is named by \tcode{std::ptrdiff_t} in the \libheader{cstddef} header\iref{support.types.layout}. \begin{itemize} @@ -6514,13 +6943,11 @@ \end{bnf} % The -lvalue-to-rvalue\iref{conv.lval}, -array-to-pointer\iref{conv.array}, +lvalue-to-rvalue\iref{conv.lval} and function-to-pointer\iref{conv.func} standard conversions are performed on the operands. -The comparison is deprecated if -both operands were of array type -prior to these conversions\iref{depr.array.comp}. +If one of the operands is a pointer, the +array-to-pointer conversion\iref{conv.array} is performed on the other operand. \pnum The converted operands shall have arithmetic, enumeration, or pointer type. @@ -6532,8 +6959,10 @@ \pnum The usual arithmetic conversions\iref{expr.arith.conv} are performed on operands of arithmetic -or enumeration type. If both operands are pointers, pointer -conversions\iref{conv.ptr} and qualification conversions\iref{conv.qual} +or enumeration type. If both converted operands are pointers, +pointer conversions\iref{conv.ptr}, +function pointer conversions\iref{conv.fctptr}, and +qualification conversions\iref{conv.qual} are performed to bring them to their composite pointer type\iref{expr.type}. After conversions, the operands shall have the same type. @@ -6576,8 +7005,10 @@ Otherwise, the result of each of the operators is unspecified. \begin{note} A relational operator applied -to unequal function pointers or to unequal pointers to \tcode{void} +to unequal function pointers yields an unspecified result. +A pointer value of type ``pointer to \cv{}~\keyword{void}'' +can point to an object\iref{basic.compound}. \end{note} \pnum @@ -6601,17 +7032,15 @@ The \tcode{==} (equal to) and the \tcode{!=} (not equal to) operators group left-to-right. The -lvalue-to-rvalue\iref{conv.lval}, -array-to-pointer\iref{conv.array}, +lvalue-to-rvalue\iref{conv.lval} and function-to-pointer\iref{conv.func} standard conversions are performed on the operands. -The comparison is deprecated if -both operands were of array type -prior to these conversions\iref{depr.array.comp}. +If one of the operands is a pointer or a null pointer constant\iref{conv.ptr}, +the array-to-pointer conversion\iref{conv.array} is performed +on the other operand. \pnum -The converted operands shall have arithmetic, enumeration, pointer, -or pointer-to-member type, or type \tcode{std::nullptr_t}. The operators +The converted operands shall have scalar type. The operators \tcode{==} and \tcode{!=} both yield \keyword{true} or \keyword{false}, i.e., a result of type \keyword{bool}. In each case below, the operands shall have the same type after the specified conversions have been applied. @@ -6619,7 +7048,7 @@ \pnum \indextext{comparison!pointer}% \indextext{comparison!pointer to function}% -If at least one of the operands is a pointer, +If at least one of the converted operands is a pointer, pointer conversions\iref{conv.ptr}, function pointer conversions\iref{conv.fctptr}, and qualification conversions\iref{conv.qual} @@ -6943,13 +7372,18 @@ formed and at least one of the operands has (possibly cv-qualified) class type: \begin{itemize} \item if \tcode{T1} and \tcode{T2} are the same class type -(ignoring cv-qualification) and -\tcode{T2} is at least as cv-qualified as \tcode{T1}, -the target type is \tcode{T2}, +(ignoring cv-qualification): + \begin{itemize} + \item + if \tcode{T2} is at least as cv-qualified as \tcode{T1}, + the target type is \tcode{T2}, + \item + otherwise, no conversion sequence is formed for this operand; + \end{itemize} \item otherwise, if \tcode{T2} is a base class of \tcode{T1}, the target type is \cvqual{cv1} \tcode{T2}, where \cvqual{cv1} -denotes the cv-qualifiers of \tcode{T1}, +denotes the cv-qualifiers of \tcode{T1}; \item otherwise, the target type is the type that \tcode{E2} would have after applying the @@ -6962,12 +7396,14 @@ Using this process, it is determined whether an implicit conversion sequence can be formed from the second operand -to the target type determined for the third operand, and vice versa. -If both sequences can be formed, or one can be formed but it is the +to the target type determined for the third operand, and vice versa, +with the following outcome: +\begin{itemize} +\item If both sequences can be formed, or one can be formed but it is the ambiguous conversion sequence, the program is ill-formed. -If no conversion sequence can be formed, the operands are left unchanged +\item If no conversion sequence can be formed, the operands are left unchanged and further checking is performed as described below. -Otherwise, if exactly one conversion sequence can be formed, +\item Otherwise, if exactly one conversion sequence can be formed, that conversion is applied to the chosen operand and the converted operand is used in place of the original operand for the remainder of this subclause. @@ -6975,6 +7411,7 @@ The conversion might be ill-formed even if an implicit conversion sequence could be formed. \end{note} +\end{itemize} \pnum If the second and third operands are glvalues of the same value category @@ -6993,30 +7430,32 @@ subclause. \pnum -Lvalue-to-rvalue\iref{conv.lval}, array-to-pointer\iref{conv.array}, +Array-to-pointer\iref{conv.array} and function-to-pointer\iref{conv.func} standard conversions are performed on the second and third operands. After those conversions, one of the following shall hold: \begin{itemize} \item The second and third operands have the same type; the result is of -that type and the result object is initialized using the selected operand. +that type and the result is copy-initialized using the selected operand. \item The second and third operands have arithmetic or enumeration type; the usual arithmetic conversions\iref{expr.arith.conv} are performed to bring them to a common type, and the result is of that type. \item One or both of the second and third operands have pointer type; -pointer conversions\iref{conv.ptr}, -function pointer conversions\iref{conv.fctptr}, and +lvalue-to-rvalue\iref{conv.lval}, +pointer\iref{conv.ptr}, +function pointer\iref{conv.fctptr}, and qualification conversions\iref{conv.qual} are performed to bring them to their composite pointer type\iref{expr.type}. The result is of the composite pointer type. \item One or both of the second and third operands have pointer-to-member type; -pointer to member conversions\iref{conv.mem}, -function pointer conversions\iref{conv.fctptr}, and +lvalue-to-rvalue\iref{conv.lval}, +pointer to member\iref{conv.mem}, +function pointer\iref{conv.fctptr}, and qualification conversions\iref{conv.qual} are performed to bring them to their composite pointer type\iref{expr.type}. The result is of the composite pointer type. @@ -7131,7 +7570,7 @@ \end{codeblock} \end{example} -\rSec2[expr.ass]{Assignment and compound assignment operators}% +\rSec2[expr.assign]{Assignment and compound assignment operators}% \indextext{expression!assignment and compound assignment} \pnum @@ -7183,9 +7622,13 @@ \end{bnf} \pnum -In simple assignment (\tcode{=}), the object referred to by the left operand -is modified\iref{defns.access} -by replacing its value with the result of the right operand. +In simple assignment (\tcode{=}), +let \tcode{V} be the result of the right operand; +the object referred to by the left operand is +modified\iref{defns.access} by replacing its value +with \tcode{V} or, +if the object is of integer type, +with the value congruent\iref{basic.fundamental} to \tcode{V}. \pnum \indextext{assignment!conversion by}% @@ -7231,17 +7674,22 @@ \end{note} \pnum -A \grammarterm{braced-init-list} may appear on the right-hand side of +A \grammarterm{braced-init-list} $B$ may appear on the right-hand side of + \begin{itemize} -\item an assignment to a scalar, in which case the initializer list shall have -at most a single element. The meaning of \tcode{x = \{v\}}, where \tcode{T} is the -scalar type of the expression \tcode{x}, is that of \tcode{x = T\{v\}}. The meaning of -\tcode{x = \{\}} is \tcode{x = T\{\}}. - -\item an assignment to an object of class type, in which case the initializer -list is passed as the argument to the assignment operator function selected by -overload resolution\iref{over.ass,over.match}. +\item +an assignment to a scalar of type \tcode{T}, in which case $B$ +shall have at most a single element. +The meaning of \tcode{x = $B$} is \tcode{x = t}, +where \tcode{t} is an invented temporary variable +declared and initialized as \tcode{T t = $B$}. + +\item +an assignment to an object of class type, in which case $B$ +is passed as the argument to the assignment operator function selected by +overload resolution\iref{over.assign,over.match}. \end{itemize} + \begin{example} \begin{codeblock} complex z; @@ -7320,27 +7768,149 @@ \end{bnf} \pnum -A variable or temporary object \tcode{o} is \defn{constant-initialized} if +The \defnx{constituent values}{constituent value} of an object $o$ are +\begin{itemize} +\item +if $o$ has scalar type, the value of $o$; +\item +otherwise, the constituent values of any direct subobjects of $o$ +other than inactive union members. +\end{itemize} +The \defnx{constituent references}{constituent reference} of an object $o$ are +\begin{itemize} +\item +any direct members of $o$ that have reference type, and +\item +the constituent references of any direct subobjects of $o$ +other than inactive union members. +\end{itemize} + +\pnum +The constituent values and constituent references of +a variable \tcode{x} are defined as follows: \begin{itemize} \item - either it has an initializer or - its default-initialization results in some initialization being performed, and -\item - the full-expression of its initialization is a constant expression - when interpreted as a \grammarterm{constant-expression}, - except that if \tcode{o} is an object, - that 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 can have a non-trivial destructor. - Within this evaluation, - \tcode{std::is_constant_evaluated()}\iref{meta.const.eval} - returns \keyword{true}. +If \tcode{x} declares an object, +the constituent values and references of that object are +constituent values and references of \tcode{x}. +\item +If \tcode{x} declares a reference, +that reference is a constituent reference of \tcode{x}. +\end{itemize} +For any constituent reference \tcode{r} of a variable \tcode{x}, +if \tcode{r} is bound to a temporary object or subobject thereof +whose lifetime is extended to that of \tcode{r}, +the constituent values and references of that temporary object +are also constituent values and references of \tcode{x}, recursively. + +\pnum +An object $o$ is \defn{constexpr-referenceable} from a point $P$ if +\begin{itemize} +\item +$o$ has static storage duration, or +\item +$o$ has automatic storage duration, and, letting \tcode{v} denote +\begin{itemize} +\item +the variable corresponding to $o$'s complete object or +\item +the variable to whose lifetime that of $o$ is extended, +\end{itemize} +the smallest scope enclosing \tcode{v} and the smallest scope enclosing $P$ +that are neither +\begin{itemize} +\item +block scopes nor +\item +function parameter scopes associated with +a \grammarterm{requirement-parameter-list} +\end{itemize} +are the same function parameter scope. +\end{itemize} +\begin{example} +\begin{codeblock} +struct A { + int m; + const int& r; +}; +void f() { + static int sx; + thread_local int tx; // \tcode{tx} is never constexpr-referenceable + int ax; + A aa = {1, 2}; + static A sa = {3, 4}; + // The objects \tcode{sx}, \tcode{ax}, and \tcode{aa.m}, \tcode{sa.m}, and the temporaries to which \tcode{aa.r} and \tcode{sa.r} are bound, are constexpr-referenceable. + auto lambda = [] { + int ay; + // The objects \tcode{sx}, \tcode{sa.m}, and \tcode{ay} (but not \tcode{ax} or \tcode{aa}), and the + // temporary to which \tcode{sa.r} is bound, are constexpr-referenceable. + }; +} +\end{codeblock} +\end{example} + +\pnum +An object or reference \tcode{x} is +\defn{constexpr-representable} at a point $P$ if, +for each constituent value of \tcode{x} that points to or past an object $o$, +and for each constituent reference of \tcode{x} that refers to an object $o$, +$o$ is constexpr-referenceable from $P$. + +\pnum +\indextext{contract evaluation semantics!ignore} +A variable \tcode{v} is \defn{constant-initializable} if +\begin{itemize} +\item +the full-expression of its initialization is a constant expression +when interpreted as a \grammarterm{constant-expression} +with all contract assertions +using the ignore evaluation semantic\iref{basic.contract.eval}, +\begin{note} +Within this evaluation, +\tcode{std::is_constant_evaluated()}\iref{meta.const.eval} +returns \keyword{true}. +\end{note} +\begin{note} +The initialization, when evaluated, +can still evaluate contract assertions +with other evaluation semantics, +resulting in a diagnostic or ill-formed program +if a contract violation occurs. \end{note} +\item +immediately after the initializing declaration of \tcode{v}, +the object or reference \tcode{x} declared by \tcode{v} +is constexpr-representable, and +\item +if \tcode{x} has static or thread storage duration, +\tcode{x} is constexpr-representable at the nearest point +whose immediate scope is a namespace scope +that follows the initializing declaration of \tcode{v}. \end{itemize} +\pnum +A constant-initializable variable is \defn{constant-initialized} +if either it has an initializer or +its type is const-default-constructible\iref{dcl.init.general}. +\begin{example} +\begin{codeblock} +void f() { + int ax = 0; // \tcode{ax} is constant-initialized + thread_local int tx = 0; // \tcode{tx} is constant-initialized + static int sx; // \tcode{sx} is not constant-initialized + static int& rss = sx; // \tcode{rss} is constant-initialized + static int& rst = tx; // \tcode{rst} is not constant-initialized + static int& rsa = ax; // \tcode{rsa} is not constant-initialized + thread_local int& rts = sx; // \tcode{rts} is constant-initialized + thread_local int& rtt = tx; // \tcode{rtt} is not constant-initialized + thread_local int& rta = ax; // \tcode{rta} is not constant-initialized + int& ras = sx; // \tcode{ras} is constant-initialized + int& rat = tx; // \tcode{rat} is not constant-initialized + int& raa = ax; // \tcode{raa} is constant-initialized +} +\end{codeblock} +\end{example} + \pnum A variable is \defn{potentially-constant} if it is constexpr or @@ -7355,16 +7925,43 @@ \item $V$ is not initialized to a TU-local value, or \item $P$ is in the same translation unit as $D$. \end{itemize} -An object or reference is \defn{usable in constant expressions} if it is +An object or reference is +\defn{potentially usable in constant expressions} at point $P$ 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 temporary object of non-volatile const-qualified literal type - whose lifetime is extended\iref{class.temporary} - to that of a variable that is usable in constant expressions, or -\item a non-mutable subobject or reference member of any of the above. +\item +the object or reference declared by a variable +that is usable in constant expressions at $P$, +\item +a temporary object of non-volatile const-qualified literal type +whose lifetime is extended\iref{class.temporary} +to that of a variable that is usable in constant expressions at $P$, +\item +a template parameter object\iref{temp.param}, +\item +a string literal object\iref{lex.string}, +\item +a non-mutable subobject of any of the above, or +\item +a reference member of any of the above. \end{itemize} +An object or reference is \defn{usable in constant expressions} at point $P$ +if it is an object or reference +that is potentially usable in constant expressions at $P$ and +is constexpr-representable at $P$. +\begin{example} +\begin{codeblock} +struct A { + int* const & r; +}; +void f(int x) { + constexpr A a = {&x}; + static_assert(a.r == &x); // OK + [&] { + static_assert(a.r != nullptr); // error: \tcode{a.r} is not usable in constant expressions at this point + }(); +} +\end{codeblock} +\end{example} \pnum An expression $E$ is a \defnadj{core constant}{expression} @@ -7422,9 +8019,8 @@ limits (see \ref{implimits}); \item -an operation that would have undefined behavior -as specified in \ref{intro} through \ref{cpp}, -excluding \ref{dcl.attr.assume}; +an operation that would have undefined or erroneous behavior +as specified in \ref{intro} through \ref{\lastcorechapter}; \begin{footnote} This includes, for example, signed integer overflow\iref{expr.pre}, certain @@ -7436,6 +8032,9 @@ an lvalue-to-rvalue conversion\iref{conv.lval} unless it is applied to \begin{itemize} + \item + a glvalue of type \cv{}~\tcode{std::nullptr_t}, + \item a non-volatile glvalue that refers to an object that is usable in constant expressions, or @@ -7480,7 +8079,8 @@ \begin{note} If the odr-use occurs in an invocation of a function call operator of a closure type, -it no longer refers to \keyword{this} or to an enclosing automatic variable +it no longer refers to \keyword{this} or to an enclosing +variable with automatic storage duration due to the transformation\iref{expr.prim.lambda.capture} of the \grammarterm{id-expression} into an access of the corresponding data member. @@ -7500,14 +8100,17 @@ \item a conversion from a prvalue \tcode{P} of type ``pointer to \cv{}~\keyword{void}'' -to a pointer-to-object type \tcode{T} -unless \tcode{P} points to an object whose type is similar to \tcode{T}; +to a type ``\cvqual{cv1} pointer to \tcode{T}'', +where \tcode{T} is not \cvqual{cv2}~\keyword{void}, +unless \tcode{P} +is a null pointer value or +points to an object whose type is similar to \tcode{T}; \item a \keyword{reinterpret_cast}\iref{expr.reinterpret.cast}; \item -a modification of an object\iref{expr.ass,expr.post.incr,expr.pre.incr} +a modification of an object\iref{expr.assign,expr.post.incr,expr.pre.incr} unless it is applied to a non-volatile lvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of $E$; @@ -7519,9 +8122,27 @@ \item a \grammarterm{new-expression}\iref{expr.new}, -unless the selected allocation function is +unless either +\begin{itemize} +\item +the selected allocation function is a replaceable global allocation function\iref{new.delete.single,new.delete.array} and -the allocated storage is deallocated within the evaluation of $E$; +the allocated storage is deallocated within the evaluation of $E$, or +\item +the selected allocation function is +a non-allocating form\iref{new.delete.placement} +with an allocated type \tcode{T}, where +\begin{itemize} +\item +the placement argument to the \grammarterm{new-expression} points to +an object whose type is similar to \tcode{T}\iref{conv.qual} or, +if \tcode{T} is an array type, +to the first element of an object of a type similar to \tcode{T}, and +\item +the placement argument points to storage +whose duration began within the evaluation of $E$; +\end{itemize} +\end{itemize} \item a \grammarterm{delete-expression}\iref{expr.delete}, @@ -7539,6 +8160,13 @@ unless it deallocates a region of storage allocated within the evaluation of $E$; +\item +a construction of an exception object, +unless the exception object and +all of its implicit copies created by invocations of +\tcode{std::current_exception} or \tcode{std::rethrow_exception}\iref{propagation} +are destroyed within the evaluation of $E$; + \item an \grammarterm{await-expression}\iref{expr.await}; @@ -7550,21 +8178,24 @@ relational\iref{expr.rel}, or equality\iref{expr.eq} operator where the result is unspecified; -\item -a \grammarterm{throw-expression}\iref{expr.throw}; - \item a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or \keyword{typeid}\iref{expr.typeid} expression on a glvalue that refers to an object -whose dynamic type is constexpr-unknown or -that would throw an exception; +whose dynamic type is constexpr-unknown; + +\item +a \tcode{dynamic_cast}\iref{expr.dynamic.cast} expression, +\tcode{typeid}\iref{expr.typeid} expression, or +\tcode{new-expression}\iref{expr.new} +that would throw an exception +where no definition of the exception type is reachable; \item an \grammarterm{asm-declaration}\iref{dcl.asm}; \item -an invocation of the \tcode{va_arg} macro\iref{cstdarg.syn}; +an invocation of the \libmacro{va_arg} macro\iref{cstdarg.syn}; \item a non-constant library call\iref{defns.nonconst.libcall}; @@ -7573,35 +8204,33 @@ \item a \keyword{goto} statement\iref{stmt.goto}. \begin{note} -A \keyword{goto} statement introduced by equivalence\iref{stmt.stmt} +A \keyword{goto} statement introduced by equivalence\iref{stmt} is not in scope. For example, a \keyword{while} statement\iref{stmt.while} can be executed during constant evaluation. \end{note} \end{itemize} +\pnum +It is +\impldef{whether an expression is a core constant expression} +whether $E$ is a core constant expression +if $E$ satisfies the constraints of a core constant expression, but +evaluation of $E$ has runtime-undefined behavior. + +\pnum It is unspecified whether $E$ is a core constant expression if $E$ satisfies the constraints of a core constant expression, but evaluation of $E$ would evaluate \begin{itemize} \item an operation that has undefined behavior -as specified in \ref{library} through \ref{\lastlibchapter}, -\item -an invocation of the \tcode{va_start} macro\iref{cstdarg.syn}, or +as specified in \ref{library} through \ref{\lastlibchapter} or \item -a statement with an assumption\iref{dcl.attr.assume} -whose converted \grammarterm{conditional-expression}, -if evaluated where the assumption appears, -would not disqualify $E$ from being a core constant expression and -would not evaluate to \tcode{true}. -\begin{note} -$E$ is not disqualified from being a core constant expression -if the hypothetical evaluation of -the converted \grammarterm{conditional-expression} -would disqualify $E$ from being a core constant expression. -\end{note} +an invocation of the \libmacro{va_start} macro\iref{cstdarg.syn}. \end{itemize} + +\pnum \begin{example} \begin{codeblock} int x; // not constant @@ -7648,14 +8277,6 @@ the evaluation of the body of a member function of \tcode{std::allocator} as defined in \ref{allocator.members}, where \tcode{T} is a literal type, is ignored. -Similarly, the evaluation of the body of -\tcode{std::construct_at} or -\tcode{std::ranges::construct_at} -is considered to include only -the initialization of the \tcode{T} object -if the first argument (of type \tcode{T*}) points -to storage allocated with \tcode{std::allocator} or -to an object whose lifetime began within the evaluation of $E$. \pnum For the purposes of determining whether $E$ is a core constant expression, @@ -7666,6 +8287,45 @@ The copy/move of the active member is trivial. \end{note} +\pnum +For the purposes of determining whether $E$ is a core constant expression, +the evaluation of an \grammarterm{id-expression} +that names a structured binding \tcode{v}\iref{dcl.struct.bind} has the +following semantics: +\begin{itemize} +\item +If \tcode{v} is an lvalue referring to the object bound to an invented reference \tcode{r}, +the behavior is as if \tcode{r} were nominated. +\item +Otherwise, if \tcode{v} names an array element or class member, +the behavior is that of +evaluating \tcode{$e$[$i$]} or \tcode{$e$.$m$}, respectively, +where $e$ is the name of the variable +initialized from the initializer of the structured binding declaration, and +$i$ is the index of the element referred to by \tcode{v} or +$m$ is the name of the member referred to by \tcode{v}, respectively. +\end{itemize} +\begin{example} +\begin{codeblock} +#include +struct S { + mutable int m; + constexpr S(int m): m(m) {} + virtual int g() const; +}; +void f(std::tuple t) { + auto [r] = t; + static_assert(r.g() >= 0); // error: dynamic type is constexpr-unknown + constexpr auto [m] = S(1); + static_assert(m == 1); // error: lvalue-to-rvalue conversion on mutable + // subobject \tcode{e.m}, where \tcode{e} is a constexpr object of type \tcode{S} + using A = int[2]; + constexpr auto [v0, v1] = A{2, 3}; + static_assert(v0 + v1 == 5); // OK, equivalent to \tcode{e[0] + e[1]} where \tcode{e} is a constexpr array +} +\end{codeblock} +\end{example} + \pnum During the evaluation of an expression $E$ as a core constant expression, all \grammarterm{id-expression}s and uses of \tcode{*\keyword{this}} @@ -7736,13 +8396,13 @@ \end{example} \pnum -An object \tcode{a} is said to have \defnadj{constant}{destruction} if: +An object \tcode{a} is said to have \defnadj{constant}{destruction} if \begin{itemize} \item it is not of class type nor (possibly multidimensional) array thereof, or \item it is of class type or (possibly multidimensional) array thereof, - that class type has a constexpr destructor, and + that class type has a constexpr destructor\iref{dcl.constexpr}, and for a hypothetical expression $E$ whose only effect is to destroy \tcode{a}, $E$ would be a core constant expression @@ -7796,6 +8456,9 @@ \item qualification conversions\iref{conv.qual}, \item integral promotions\iref{conv.prom}, \item integral conversions\iref{conv.integral} other than narrowing conversions\iref{dcl.init.list}, +\item floating-point promotions\iref{conv.fpprom}, +\item floating-point conversions\iref{conv.double} where + the source value can be represented exactly in the destination type, \item null pointer conversions\iref{conv.ptr} from \tcode{std::nullptr_t}, \item null member pointer conversions\iref{conv.mem} from \tcode{std::nullptr_t}, and \item function pointer conversions\iref{conv.fctptr}, @@ -7806,7 +8469,7 @@ expressions\iref{expr.new}, as case expressions\iref{stmt.switch}, as enumerator initializers if the underlying type is fixed\iref{dcl.enum}, as array bounds\iref{dcl.array}, and -as non-type template +as constant template arguments\iref{temp.arg}. \end{note} \indextext{contextually converted constant expression of type \tcode{bool}|see{conversion, contextual}}% @@ -7819,40 +8482,20 @@ \pnum A \defnadj{constant}{expression} is either a glvalue core constant expression that refers to -an entity that is a permitted result of a constant expression (as defined below), or -a prvalue core constant expression whose value +an object or a non-immediate function, or +a prvalue core constant expression whose result object\iref{basic.lval} satisfies the following constraints: \begin{itemize} - \item - if the value is an object of class type, - each non-static data member of reference type refers to - an entity that is a permitted result of a constant expression, - - \item - if the value is an object of scalar type, - it does not have an indeterminate value\iref{basic.indet}, - - \item - if the value is of pointer type, it contains - the address of an object with static storage duration, - the address past the end of such an object\iref{expr.add}, - the address of a non-immediate function, - or a null pointer value, - - \item - if the value is of pointer-to-member-function type, - it does not designate an immediate function, and - - \item - if the value is an object of class or array type, - each subobject satisfies these constraints for the value. +\item +each constituent reference refers to an object or a non-immediate function, +\item +no constituent value of scalar type is an indeterminate or erroneous value\iref{basic.indet}, +\item +no constituent value of pointer type is a pointer to an immediate function or +an invalid pointer value\iref{basic.compound}, and +\item +no constituent value of pointer-to-member type designates an immediate function. \end{itemize} -An entity is a -\defnx{permitted result of a constant expression}{constant expression!permitted result of} -if it is an -object with static storage duration that either is not a temporary object or is -a temporary object whose value satisfies the above constraints, or if -it is a non-immediate function. \begin{note} A glvalue core constant expression that either refers to or points to an unspecified object @@ -7866,6 +8509,14 @@ constexpr int r = h(); // OK constexpr auto e = g(); // error: a pointer to an immediate function is // not a permitted result of a constant expression + +struct S { + int x; + constexpr S() {} +}; +int i() { + constexpr S s; // error: \tcode{s.x} has erroneous value +} \end{codeblock} \end{example} @@ -7959,6 +8610,11 @@ whose function body contains an immediate-escalating expression \tcode{\placeholder{E}} such that \tcode{\placeholder{E}}'s innermost enclosing non-block scope is \tcode{\placeholder{F}}'s function parameter scope. +\begin{tailnote} +Default member initializers used to initialize +a base or member subobject\iref{class.base.init} +are considered to be part of the function body\iref{dcl.fct.def.general}. +\end{tailnote} \end{itemize} \begin{example} \begin{codeblock} @@ -8014,6 +8670,15 @@ constexpr int k(int) { // \tcode{k} is not an immediate function because \tcode{A(42)} is a return A(42).y; // constant expression and thus not immediate-escalating } + +constexpr int l(int c) pre(c >= 2) { + return (c % 2 == 0) ? c / 0 : c; +} + +const int i0 = l(0); // dynamic initialization; contract violation or undefined behavior +const int i1 = l(1); // static initialization; value of \tcode{1} or contract violation at compile time +const int i2 = l(2); // dynamic initialization; undefined behavior +const int i3 = l(3); // static initialization; value of \tcode{3} \end{codeblock} \end{example} @@ -8032,7 +8697,10 @@ has constant initialization\iref{basic.start.static}. \begin{footnote} Testing this condition -can involve a trial evaluation of its initializer as described above. +can involve a trial evaluation of its initializer, +with evaluations of contract assertions +using the ignore evaluation semantic\iref{basic.contract.eval}, +as described above. \end{footnote} \begin{example} \begin{codeblock} @@ -8057,7 +8725,8 @@ \end{example} \end{itemize} \begin{note} -A manifestly constant-evaluated expression +Except for a \grammarterm{static_assert-message}, +a manifestly constant-evaluated expression is evaluated even in an unevaluated operand\iref{term.unevaluated.operand}. \end{note} diff --git a/source/future.tex b/source/future.tex index 450109745c..50edea0be7 100644 --- a/source/future.tex +++ b/source/future.tex @@ -4,8 +4,8 @@ \rSec1[depr.general]{General} \pnum -This Annex describes features of the \Cpp{} Standard that are specified for compatibility with -existing implementations. +This Annex describes features of this document +that are specified for compatibility with existing implementations. \pnum These are deprecated features, where @@ -16,24 +16,23 @@ An implementation may declare library names and entities described in this Clause with the \tcode{deprecated} attribute\iref{dcl.attr.deprecated}. -\rSec1[depr.arith.conv.enum]{Arithmetic conversion on enumerations} +\rSec1[depr.local]{Non-local use of TU-local entities} \pnum -The ability to apply the usual arithmetic conversions\iref{expr.arith.conv} -on operands where one is of enumeration type -and the other is of a different enumeration type -or a floating-point type +A declaration of a non-TU-local entity that is an exposure\iref{basic.link} is deprecated. \begin{note} -Three-way comparisons\iref{expr.spaceship} between such operands are ill-formed. +Such a declaration in an importable module unit is ill-formed. \end{note} \begin{example} \begin{codeblock} -enum E1 { e }; -enum E2 { f }; -bool b = e <= 3.7; // deprecated -int k = f - e; // deprecated -auto cmp = e <=> f; // error +namespace { + struct A { + void f() {} + }; +} +A h(); // deprecated: not internal linkage +inline void g() {A().f();} // deprecated: inline and not internal linkage \end{codeblock} \end{example} @@ -56,25 +55,6 @@ \end{codeblock} \end{example} -\rSec1[depr.array.comp]{Array comparisons} - -\pnum -Equality and relational comparisons\iref{expr.eq,expr.rel} -between two operands of array type -are deprecated. -\begin{note} -Three-way comparisons\iref{expr.spaceship} between such operands are ill-formed. -\end{note} -\begin{example} -\begin{codeblock} -int arr1[5]; -int arr2[5]; -bool same = arr1 == arr2; // deprecated, same as \tcode{\&arr1[0] == \&arr2[0]}, - // does not compare array contents -auto cmp = arr1 <=> arr2; // error -\end{codeblock} -\end{example} - \rSec1[depr.volatile.type]{Deprecated \tcode{volatile} types} \pnum @@ -93,7 +73,7 @@ \pnum Certain assignments where the left operand is a volatile-qualified non-class type -are deprecated; see~\ref{expr.ass}. +are deprecated; see~\ref{expr.assign}. \begin{example} \begin{codeblock} @@ -135,41 +115,17 @@ \end{codeblock} \end{example} +\rSec1[depr.ellipsis.comma]{Non-comma-separated ellipsis parameters} -\rSec1[depr.static.constexpr]{Redeclaration of \tcode{static constexpr} data members} - -\pnum -For compatibility with prior revisions of \Cpp{}, a \keyword{constexpr} -static data member may be redundantly redeclared outside the class with no -initializer\iref{basic.def,class.static.data}. -This usage is deprecated. -\begin{example} -\begin{codeblock} -struct A { - static constexpr int n = 5; // definition (declaration in \CppXIV{}) -}; - -constexpr int A::n; // redundant declaration (definition in \CppXIV{}) -\end{codeblock} -\end{example} - -\rSec1[depr.local]{Non-local use of TU-local entities} - -\pnum -A declaration of a non-TU-local entity that is an exposure\iref{basic.link} -is deprecated. -\begin{note} -Such a declaration in an importable module unit is ill-formed. -\end{note} +A \grammarterm{parameter-declaration-clause} +of the form +\grammarterm{parameter-declaration-list} \tcode{...} +is deprecated\iref{dcl.fct}. \begin{example} \begin{codeblock} -namespace { - struct A { - void f() {} - }; -} -A h(); // deprecated: not internal linkage -inline void g() {A().f();} // deprecated: inline and not internal linkage +void f(int...); // deprecated +void g(auto...); // OK, declares a function parameter pack +void h(auto......); // deprecated \end{codeblock} \end{example} @@ -187,12 +143,29 @@ It is possible that future versions of \Cpp{} will specify that these implicit definitions are deleted\iref{dcl.fct.def.delete}. +\rSec1[depr.static.constexpr]{Redeclaration of \tcode{static constexpr} data members} + +\pnum +For compatibility with prior revisions of \Cpp{}, a \keyword{constexpr} +static data member may be redundantly redeclared outside the class with no +initializer\iref{basic.def,class.static.data}. +This usage is deprecated. +\begin{example} +\begin{codeblock} +struct A { + static constexpr int n = 5; // definition (declaration in \CppXIV{}) +}; + +constexpr int A::n; // redundant declaration (definition in \CppXIV{}) +\end{codeblock} +\end{example} + \rSec1[depr.lit]{Literal operator function declarations using an identifier} \pnum A \grammarterm{literal-operator-id}\iref{over.literal} of the form \begin{codeblock} -operator @\grammarterm{string-literal}@ @\grammarterm{identifier}@ +operator @\grammarterm{unevaluated-string}@ @\grammarterm{identifier}@ \end{codeblock} is deprecated. @@ -208,13 +181,12 @@ \pnum The following type is defined in addition to those specified in \libheaderref{limits}: -\indexlibraryglobal{float_denorm_style}% \begin{codeblock} namespace std { - enum float_denorm_style { - denorm_indeterminate = -1, - denorm_absent = 0, - denorm_present = 1 + enum @\libglobal{float_denorm_style}@ { + @\libmember{denorm_indeterminate}{float_denorm_style}@ = -1, + @\libmember{denorm_absent}{float_denorm_style}@ = 0, + @\libmember{denorm_present}{float_denorm_style}@ = 1 }; } \end{codeblock} @@ -248,2347 +220,479 @@ \rSec1[depr.c.macros]{Deprecated C macros} \pnum -The header \libheader{stdalign.h} has the following macro: -\indexheader{stdalign.h}% -\indexlibraryglobal{__alignas_is_defined}% +The header \libheaderref{stdalign.h} has the following macros: \begin{codeblock} -#define @\xname{alignas_is_defined}@ 1 +#define @\libxmacro{alignas_is_defined}@ 1 +#define @\libxmacro{alignof_is_defined}@ 1 \end{codeblock} \pnum -The header \libheader{stdbool.h} has the following macro: -\indexheader{stdbool.h}% -\indexhdr{stdbool.h}% -\indexlibraryglobal{__bool_true_false_are_defined}% +The header \libheaderref{stdbool.h} has the following macro: \begin{codeblock} -#define @\xname{bool_true_false_are_defined}@ 1 +#define @\libxmacro{bool_true_false_are_defined}@ 1 \end{codeblock} -\rSec1[depr.relops]{Relational operators}% -\indexlibraryglobal{rel_ops}% +\rSec1[depr.cerrno]{Deprecated error numbers} \pnum -The header \libheaderref{utility} has the following additions: +The header \libheaderref{cerrno} has the following additional macros: \begin{codeblock} -namespace std::rel_ops { - template bool operator!=(const T&, const T&); - template bool operator> (const T&, const T&); - template bool operator<=(const T&, const T&); - template bool operator>=(const T&, const T&); -} +#define @\libmacro{ENODATA}@ @\seebelow@ +#define @\libmacro{ENOSR}@ @\seebelow@ +#define @\libmacro{ENOSTR}@ @\seebelow@ +#define @\libmacro{ETIME}@ @\seebelow@ \end{codeblock} \pnum -To avoid redundant definitions of \tcode{operator!=} out of \tcode{operator==} -and operators \tcode{>}, \tcode{<=}, and \tcode{>=} out of \tcode{operator<}, -the library provides the following: - -\indexlibrary{\idxcode{operator"!=}}% -\begin{itemdecl} -template bool operator!=(const T& x, const T& y); -\end{itemdecl} +The meaning of these macros is defined by the POSIX standard. -\begin{itemdescr} \pnum -\expects -\tcode{T} meets the \oldconcept{EqualityComparable} requirements (\tref{cpp17.equalitycomparable}). +The following \tcode{enum errc} enumerators are defined +in addition to those specified in \ref{system.error.syn}: + +\begin{codeblock} +@\libmember{no_message_available}{errc}@, // \tcode{ENODATA} +@\libmember{no_stream_resources}{errc}@, // \tcode{ENOSR} +@\libmember{not_a_stream}{errc}@, // \tcode{ENOSTR} +@\libmember{stream_timeout}{errc}@, // \tcode{ETIME} +\end{codeblock} \pnum -\returns -\tcode{!(x == y)}. -\end{itemdescr} +The value of each \tcode{enum errc} enumerator above +is the same as the value of the \libheader{cerrno} macro +shown in the above synopsis. -\indexlibraryglobal{operator>}% -\begin{itemdecl} -template bool operator>(const T& x, const T& y); -\end{itemdecl} +\rSec1[depr.meta.types]{Deprecated type traits} -\begin{itemdescr} \pnum -\expects -\tcode{T} meets the \oldconcept{LessThanComparable} requirements (\tref{cpp17.lessthancomparable}). +The header \libheaderrefx{type_traits}{meta.type.synop} +has the following addition: -\pnum -\returns -\tcode{y < x}. -\end{itemdescr} +\begin{codeblock} +namespace std { + template struct is_trivial; + template constexpr bool is_trivial_v = is_trivial::value; + template struct is_pod; + template constexpr bool is_pod_v = is_pod::value; + template // \seebelow + struct aligned_storage; + template // \seebelow + using @\libglobal{aligned_storage_t}@ = typename aligned_storage::type; + template + struct aligned_union; + template + using @\libglobal{aligned_union_t}@ = typename aligned_union::type; +} +\end{codeblock} -\indexlibrary{\idxcode{operator<=}}% -\begin{itemdecl} -template bool operator<=(const T& x, const T& y); -\end{itemdecl} +\pnum +The behavior of a program that adds specializations for +any of the templates defined in this subclause is undefined, +unless explicitly permitted by the specification of the corresponding template. -\begin{itemdescr} \pnum -\expects -\tcode{T} meets the \oldconcept{LessThanComparable} requirements (\tref{cpp17.lessthancomparable}). +\label{term.trivial.type}% +A \defnadj{trivial}{class} is a class that is trivially copyable and +has one or more eligible default constructors, all of which are trivial. +\begin{note} +In particular, +a trivial class does not have virtual functions or virtual base classes. +\end{note} +A \defnadj{trivial}{type} is a scalar type, a trivial class, +an array of such a type, or a cv-qualified version of one of these types. \pnum -\returns -\tcode{!(y < x)}. -\end{itemdescr} +\indextext{POD}% +A \term{POD class} is a class that is both a trivial class and a +standard-layout class, and has no non-static data members of type non-POD class +(or array thereof). A \term{POD type} is a scalar type, a POD class, an array +of such a type, or a cv-qualified version of one of these types. -\indexlibrary{\idxcode{operator>=}}% +\indexlibraryglobal{is_trivial}% \begin{itemdecl} -template bool operator>=(const T& x, const T& y); +template struct is_trivial; \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{T} meets the \oldconcept{LessThanComparable} requirements (\tref{cpp17.lessthancomparable}). - -\pnum -\returns -\tcode{!(x < y)}. -\end{itemdescr} - -\rSec1[depr.str.strstreams]{\tcode{char*} streams} - -\rSec2[depr.strstream.syn]{Header \tcode{} synopsis} - -\pnum -The header \libheaderdef{strstream} -defines types that associate stream buffers with -character array objects and assist reading and writing such objects. - -\begin{codeblock} -namespace std { - class strstreambuf; - class istrstream; - class ostrstream; - class strstream; -} -\end{codeblock} - -\rSec2[depr.strstreambuf]{Class \tcode{strstreambuf}} - -\rSec3[depr.strstreambuf.general]{General} - -\indexlibraryglobal{strstreambuf}% -\begin{codeblock} -namespace std { - class strstreambuf : public basic_streambuf { - public: - strstreambuf() : strstreambuf(0) {} - explicit strstreambuf(streamsize alsize_arg); - strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*)); - strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr); - strstreambuf(const char* gnext_arg, streamsize n); - - strstreambuf(signed char* gnext_arg, streamsize n, - signed char* pbeg_arg = nullptr); - strstreambuf(const signed char* gnext_arg, streamsize n); - strstreambuf(unsigned char* gnext_arg, streamsize n, - unsigned char* pbeg_arg = nullptr); - strstreambuf(const unsigned char* gnext_arg, streamsize n); - - virtual ~strstreambuf(); - - void freeze(bool freezefl = true); - char* str(); - int pcount(); - - protected: - int_type overflow (int_type c = EOF) override; - int_type pbackfail(int_type c = EOF) override; - int_type underflow() override; - pos_type seekoff(off_type off, ios_base::seekdir way, - ios_base::openmode which = ios_base::in | ios_base::out) override; - pos_type seekpos(pos_type sp, - ios_base::openmode which = ios_base::in | ios_base::out) override; - streambuf* setbuf(char* s, streamsize n) override; - - private: - using strstate = T1; // \expos - static const strstate allocated; // \expos - static const strstate constant; // \expos - static const strstate dynamic; // \expos - static const strstate frozen; // \expos - strstate strmode; // \expos - streamsize alsize; // \expos - void* (*palloc)(size_t); // \expos - void (*pfree)(void*); // \expos - }; -} -\end{codeblock} - -\pnum -The class -\tcode{strstreambuf} -associates the input sequence, and possibly the output sequence, with an object of some -\textit{character} -array type, whose elements store arbitrary values. -The array object has several attributes. +\tcode{remove_all_extents_t} shall be a complete type or \cv{} \keyword{void}. \pnum -\begin{note} -For the sake of exposition, these are represented as elements of a bitmask type -(indicated here as \tcode{T1}) called \tcode{strstate}. -The elements are: -\begin{itemize} -\item -\tcode{allocated}, set when a dynamic array object has been -allocated, and hence will be freed by the destructor for the -\tcode{strstreambuf} object; -\item -\tcode{constant}, set when the array object has -\keyword{const} elements, so the output sequence cannot be written; -\item -\tcode{dynamic}, set when the array object is allocated -(or reallocated) -as necessary to hold a character sequence that can change in length; -\item -\tcode{frozen}, set when the program has requested that the -array object not be altered, reallocated, or freed. -\end{itemize} -\end{note} +\remarks +\tcode{is_trivial} is a \oldconcept{UnaryTypeTrait}\iref{meta.rqmts} +with a base characteristic of \tcode{true_type} +if \tcode{T} is a trivial type, +and \tcode{false_type} otherwise. \pnum \begin{note} -For the sake of exposition, the maintained data is presented here as: -\begin{itemize} -\item -\tcode{strstate strmode}, the attributes of the array object -associated with the \tcode{strstreambuf} object; -\item -\tcode{int alsize}, the suggested minimum size for a -dynamic array object; -\item -\tcode{void* (*palloc)(size_t)}, points to the function -to call to allocate a dynamic array object; -\item -\tcode{void (*pfree)(void*)}, points to the function to -call to free a dynamic array object. -\end{itemize} +It is unspecified +whether a closure type\iref{expr.prim.lambda.closure} is a trivial type. \end{note} +\end{itemdescr} -\pnum -Each object of class -\tcode{strstreambuf} -has a -\term{seekable area}, -delimited by the pointers \tcode{seeklow} and \tcode{seekhigh}. -If \tcode{gnext} is a null pointer, the seekable area is undefined. -Otherwise, \tcode{seeklow} equals \tcode{gbeg} and -\tcode{seekhigh} is either \tcode{pend}, -if \tcode{pend} is not a null pointer, or \tcode{gend}. - -\rSec3[depr.strstreambuf.cons]{\tcode{strstreambuf} constructors} - -\indexlibraryctor{strstreambuf}% +\indexlibraryglobal{is_pod}% \begin{itemdecl} -explicit strstreambuf(streamsize alsize_arg); +template struct is_pod; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes the base class with \tcode{streambuf()}. -The postconditions of this function are indicated in \tref{depr.strstreambuf.cons.sz}. -\end{itemdescr} - -\begin{libtab2}{\tcode{strstreambuf(streamsize)} effects}{depr.strstreambuf.cons.sz} -{ll} -{Element}{Value} -\tcode{strmode} & \tcode{dynamic} \\ -\tcode{alsize} & \tcode{alsize_arg} \\ -\tcode{palloc} & a null pointer \\ -\tcode{pfree} & a null pointer \\ -\end{libtab2} +\expects +\tcode{remove_all_extents_t} shall be a complete type or \cv{} \keyword{void}. -\indexlibraryctor{strstreambuf}% -\begin{itemdecl} -strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*)); -\end{itemdecl} +\pnum +\remarks +\tcode{is_pod} is a \oldconcept{UnaryTypeTrait}\iref{meta.rqmts} +with a base characteristic of \tcode{true_type} +if \tcode{T} is a POD type, +and \tcode{false_type} otherwise. -\begin{itemdescr} \pnum -\effects -Initializes the base class with \tcode{streambuf()}. -The postconditions of this function are indicated in \tref{depr.strstreambuf.cons.alloc}. - -\begin{libtab2}{\tcode{strstreambuf(void* (*)(size_t), void (*)(void*))} effects} -{depr.strstreambuf.cons.alloc} -{ll} -{Element}{Value} -\tcode{strmode} & \tcode{dynamic} \\ -\tcode{alsize} & an unspecified value \\ -\tcode{palloc} & \tcode{palloc_arg} \\ -\tcode{pfree} & \tcode{pfree_arg} \\ -\end{libtab2} +\begin{note} +It is unspecified whether a closure type\iref{expr.prim.lambda.closure} is a POD type. +\end{note} \end{itemdescr} -\indextext{unspecified}% -\indexlibraryctor{strstreambuf}% +\indexlibraryglobal{aligned_storage}% \begin{itemdecl} -strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr); -strstreambuf(signed char* gnext_arg, streamsize n, - signed char* pbeg_arg = nullptr); -strstreambuf(unsigned char* gnext_arg, streamsize n, - unsigned char* pbeg_arg = nullptr); +template + struct aligned_storage; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes the base class with \tcode{streambuf()}. -The postconditions of this function are indicated in \tref{depr.strstreambuf.cons.ptr}. - -\begin{libtab2}{\tcode{strstreambuf(charT*, streamsize, charT*)} effects} -{depr.strstreambuf.cons.ptr} -{ll} -{Element}{Value} -\tcode{strmode} & 0 \\ -\tcode{alsize} & an unspecified value \\ -\tcode{palloc} & a null pointer \\ -\tcode{pfree} & a null pointer \\ -\end{libtab2} - -\pnum -\tcode{gnext_arg} shall point to the first element of an array -object whose number of elements \tcode{N} is determined as follows: -\begin{itemize} -\item -If -\tcode{n > 0}, -\tcode{N} is \tcode{n}. -\item -If -\tcode{n == 0}, -\tcode{N} is -\tcode{std::strlen(gnext_arg)}. -\indexlibraryglobal{strlen}% -\item -If -\tcode{n < 0}, -\tcode{N} is -\tcode{INT_MAX}. -\begin{footnote} -The function signature -\indexlibraryglobal{strlen}% -\tcode{strlen(const char*)} -is declared in \libheaderref{cstring}. -The macro \tcode{INT_MAX} is defined in \libheaderref{climits}. -\end{footnote} -\end{itemize} +The value of \exposid{default-alignment} is the most +stringent alignment requirement for any object type whose size +is no greater than \tcode{Len}\iref{basic.types}. \pnum -If \tcode{pbeg_arg} is a null pointer, the function executes: +\mandates +\tcode{Len} is not zero. +\tcode{Align} is equal to \tcode{alignof(T)} for some type \tcode{T} or +to \exposid{default-alignment}. -\begin{codeblock} -setg(gnext_arg, gnext_arg, gnext_arg + N); -\end{codeblock} +\pnum +The member typedef \tcode{type} denotes a trivial standard-layout type +suitable for use as uninitialized storage for any object +whose size is at most \tcode{Len} and +whose alignment is a divisor of \tcode{Align}. \pnum -Otherwise, the function executes: +\begin{note} +Uses of \tcode{aligned_storage::type} can be replaced +by an array \tcode{std::byte[Len]} declared with \tcode{alignas(Align)}. +\end{note} +\pnum +\begin{note} +A typical implementation would define \tcode{aligned_storage} as: \begin{codeblock} -setg(gnext_arg, gnext_arg, pbeg_arg); -setp(pbeg_arg, pbeg_arg + N); +template +struct aligned_storage { + typedef struct { + alignas(Alignment) unsigned char __data[Len]; + } type; +}; \end{codeblock} -\end{itemdescr} +\end{note} +\end{itemdescr} -\indexlibraryctor{strstreambuf}% +\indexlibraryglobal{aligned_union}% \begin{itemdecl} -strstreambuf(const char* gnext_arg, streamsize n); -strstreambuf(const signed char* gnext_arg, streamsize n); -strstreambuf(const unsigned char* gnext_arg, streamsize n); +template + struct aligned_union; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Behaves the same as -\tcode{strstreambuf((char*)gnext_arg,n)}, -except that the constructor also sets \tcode{constant} in \tcode{strmode}. -\end{itemdescr} - -\indexlibrarydtor{strstreambuf}% -\begin{itemdecl} -virtual ~strstreambuf(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Destroys an object of class -\tcode{strstreambuf}. -The function frees the dynamically allocated array object only if -\tcode{(strmode \& allocated) != 0} -and -\tcode{(strmode \& frozen) == 0}. -(\ref{depr.strstreambuf.virtuals} describes how a dynamically allocated array object is freed.) -\end{itemdescr} - -\rSec3[depr.strstreambuf.members]{Member functions} - -\indexlibrarymember{freeze}{strstreambuf}% -\begin{itemdecl} -void freeze(bool freezefl = true); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{strmode \& dynamic} is nonzero, alters the -freeze status of the dynamic array object as follows: -\begin{itemize} -\item -If \tcode{freezefl} is -\tcode{true}, -the function sets \tcode{frozen} in \tcode{strmode}. -\item -Otherwise, it clears \tcode{frozen} in \tcode{strmode}. -\end{itemize} -\end{itemdescr} - -\indexlibrarymember{str}{strstreambuf}% -\begin{itemdecl} -char* str(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls -\tcode{freeze()}, -then returns the beginning pointer for the input sequence, \tcode{gbeg}. - -\pnum -\remarks -The return value can be a null pointer. -\end{itemdescr} - -\indexlibrarymember{pcount}{strstreambuf}% -\begin{itemdecl} -int pcount() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If the next pointer for the output sequence, \tcode{pnext}, is -a null pointer, returns zero. -Otherwise, returns the current -effective length of the array object as the next pointer minus the beginning -pointer for the output sequence, \tcode{pnext - pbeg}. -\end{itemdescr} - -\rSec3[depr.strstreambuf.virtuals]{\tcode{strstreambuf} overridden virtual functions} - -\indexlibrarymember{overflow}{strstreambuf}% -\begin{itemdecl} -int_type overflow(int_type c = EOF) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Appends the character designated by \tcode{c} to the output -sequence, if possible, in one of two ways: -\begin{itemize} -\item -If -\tcode{c != EOF} -and if either the output sequence has a write position available or -the function makes a write position available -(as described below), -assigns \tcode{c} to -\tcode{*pnext++}. - -Returns -\tcode{(unsigned char)c}. - -\item -If -\tcode{c == EOF}, -there is no character to append. - -Returns a value other than \tcode{EOF}. -\end{itemize} - -\pnum -Returns -\tcode{EOF} -to indicate failure. - -\pnum -\remarks -The function can alter the number of write positions available as a -result of any call. - -\pnum -To make a write position available, the function reallocates -(or initially allocates) -an array object with a sufficient number of elements -\tcode{n} to hold the current array object (if any), -plus at least one additional write position. -How many additional write positions are made -available is otherwise unspecified.% -\indextext{unspecified}% -If \tcode{palloc} is not a null pointer, the function calls -\tcode{(*palloc)(n)} -to allocate the new dynamic array object. -Otherwise, it evaluates the expression -\tcode{new charT[n]}. -In either case, if the allocation fails, the function returns -\tcode{EOF}. -Otherwise, it sets \tcode{allocated} in \tcode{strmode}. - -\pnum -To free a previously existing dynamic array object whose first -element address is \tcode{p}: -If \tcode{pfree} is not a null pointer, -the function calls -\tcode{(*pfree)(p)}. -Otherwise, it evaluates the expression \tcode{delete[]p}. - -\pnum -If -\tcode{(strmode \& dynamic) == 0}, -or if -\tcode{(strmode \& frozen) != 0}, -the function cannot extend the array (reallocate it with greater length) to make a write position available. - -\pnum -\recommended -An implementation should consider \tcode{alsize} in making the -decision how many additional write positions to make available. -\end{itemdescr} - -\indexlibrarymember{pbackfail}{strstreambuf}% -\begin{itemdecl} -int_type pbackfail(int_type c = EOF) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Puts back the character designated by \tcode{c} to the input -sequence, if possible, in one of three ways: -\begin{itemize} -\item -If -\tcode{c != EOF}, -if the input sequence has a putback position available, and if -\tcode{(char)c == gnext[-1]}, -assigns -\tcode{gnext - 1} -to \tcode{gnext}. - -Returns \tcode{c}. -\item -If -\tcode{c != EOF}, -if the input sequence has a putback position available, and if -\tcode{strmode \& constant} is zero, -assigns \tcode{c} to -\tcode{*--gnext}. - -Returns -\tcode{c}. -\item -If -\tcode{c == EOF} -and if the input sequence has a putback position available, -assigns -\tcode{gnext - 1} -to \tcode{gnext}. - -Returns a value other than -\tcode{EOF}. -\end{itemize} - -\pnum -Returns -\tcode{EOF} -to indicate failure. - -\pnum -\remarks -If the function can succeed in more than one of these ways, it is -unspecified which way is chosen. -\indextext{unspecified}% -The function can alter the number of putback -positions available as a result of any call. -\end{itemdescr} - -\indexlibrarymember{underflow}{strstreambuf}% -\begin{itemdecl} -int_type underflow() override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Reads a character from the -\term{input sequence}, -if possible, without moving the stream position past it, as follows: -\begin{itemize} -\item -If the input sequence has a read position available, the function -signals success by returning -\tcode{(unsigned char)\brk*gnext}. -\item -Otherwise, if -the current write next pointer \tcode{pnext} is not a null pointer and -is greater than the current read end pointer \tcode{gend}, -makes a -\term{read position} -available by -assigning to \tcode{gend} a value greater than \tcode{gnext} and -no greater than \tcode{pnext}. - -Returns \tcode{(unsigned char)*gnext}. -\end{itemize} - -\pnum -Returns -\tcode{EOF} -to indicate failure. - -\pnum -\remarks -The function can alter the number of read positions available as a -result of any call. -\end{itemdescr} - -\indexlibrarymember{seekoff}{strstreambuf}% -\begin{itemdecl} -pos_type seekoff(off_type off, seekdir way, openmode which = in | out) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Alters the stream position within one of the -controlled sequences, if possible, as indicated in \tref{depr.strstreambuf.seekoff.pos}. - -\begin{libtab2}{\tcode{seekoff} positioning}{depr.strstreambuf.seekoff.pos} -{p{2.5in}l}{Conditions}{Result} -\tcode{(which \& ios::in) != 0} & - positions the input sequence \\ \rowsep -\tcode{(which \& ios::out) != 0} & - positions the output sequence \\ \rowsep -\tcode{(which \& (ios::in | ios::out)) ==}\br -\tcode{(ios::in | ios::out)} and either\br -\tcode{way == ios::beg} or \tcode{way == ios::end} & - positions both the input and the output sequences \\ \rowsep -Otherwise & - the positioning operation fails. \\ -\end{libtab2} - -\pnum -For a sequence to be positioned, if its next pointer is a null pointer, -the positioning operation fails. -Otherwise, the function determines \tcode{newoff} as indicated in -\tref{depr.strstreambuf.seekoff.newoff}. - -\begin{libtab2}{\tcode{newoff} values}{depr.strstreambuf.seekoff.newoff} -{p{2.0in}p{2.0in}}{Condition}{\tcode{newoff} Value} -\tcode{way == ios::beg} & - 0 \\ \rowsep -\tcode{way == ios::cur} & - the next pointer minus the beginning pointer (\tcode{xnext - xbeg}). \\ \rowsep -\tcode{way == ios::end} & - \tcode{seekhigh} minus the beginning pointer (\tcode{seekhigh - xbeg}). \\ -\end{libtab2} - -\pnum -If \tcode{(newoff + off) < (seeklow - xbeg)} -or \tcode{(seekhigh - xbeg) < (newoff + off)}, -the positioning operation fails. -Otherwise, the function assigns -\tcode{xbeg + newoff + off} -to the next pointer \tcode{xnext}. - -\pnum -\returns -\tcode{pos_type(newoff)}, -constructed from the resultant offset -\tcode{newoff} (of type -\tcode{off_type}), -that stores the resultant stream position, if possible. -If the positioning operation fails, or -if the constructed object cannot represent the resultant stream position, -the return value is -\tcode{pos_type(off_type(-1))}. -\end{itemdescr} - -\indexlibrarymember{seekpos}{strstreambuf}% -\begin{itemdecl} -pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Alters the stream position within one of the -controlled sequences, if possible, to correspond to the -stream position stored in \tcode{sp} -(as described below). -\begin{itemize} -\item -If -\tcode{(which \& ios::in) != 0}, -positions the input sequence. -\item -If -\tcode{(which \& ios::out) != 0}, -positions the output sequence. -\item -If the function positions neither sequence, the positioning operation fails. -\end{itemize} - -\pnum -For a sequence to be positioned, if its next pointer is a null pointer, -the positioning operation fails. -Otherwise, the function determines \tcode{newoff} from -\tcode{sp.offset()}: -\begin{itemize} -\item -If \tcode{newoff} is an invalid stream position, -has a negative value, or -has a value greater than (\tcode{seekhigh - seeklow}), -the positioning operation fails -\item -Otherwise, the function -adds \tcode{newoff} to the beginning pointer \tcode{xbeg} and -stores the result in the next pointer \tcode{xnext}. -\end{itemize} - -\pnum -\returns -\tcode{pos_type(newoff)}, -constructed from the resultant offset \tcode{newoff} -(of type -\tcode{off_type}), -that stores the resultant stream position, if possible. -If the positioning operation fails, or -if the constructed object cannot represent the resultant stream position, -the return value is -\tcode{pos_type(off_type(-1))}. -\end{itemdescr} - -\indexlibrarymember{setbuf}{strstreambuf}% -\begin{itemdecl} -streambuf* setbuf(char* s, streamsize n) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Behavior is \impldef{behavior of \tcode{strstreambuf::setbuf}}, -except that -\tcode{setbuf(0, 0)} -has no effect.% -\end{itemdescr} - -\rSec2[depr.istrstream]{Class \tcode{istrstream}} - -\rSec3[depr.istrstream.general]{General} - -\indexlibraryglobal{istrstream}% -\begin{codeblock} -namespace std { - class istrstream : public basic_istream { - public: - explicit istrstream(const char* s); - explicit istrstream(char* s); - istrstream(const char* s, streamsize n); - istrstream(char* s, streamsize n); - virtual ~istrstream(); - - strstreambuf* rdbuf() const; - char* str(); - private: - strstreambuf sb; // \expos - }; -} -\end{codeblock} - -\pnum -The class -\tcode{istrstream} -supports the reading of objects of class -\tcode{strstreambuf}. -It supplies a -\tcode{strstreambuf} -object to control the associated array object. -For the sake of exposition, the maintained data is presented here as: - -\begin{itemize} -\item -\tcode{sb}, the \tcode{strstreambuf} object. -\end{itemize} - -\rSec3[depr.istrstream.cons]{\tcode{istrstream} constructors} - -\indexlibraryctor{istrstream}% -\begin{itemdecl} -explicit istrstream(const char* s); -explicit istrstream(char* s); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the base class with \tcode{istream(\&sb)} and -\tcode{sb} with \tcode{strstreambuf(s, 0)}. -\tcode{s} shall designate the first element of an \ntbs{}.% -\indextext{NTBS@\ntbs{}} -\end{itemdescr} - -\indexlibraryctor{istrstream}% -\begin{itemdecl} -istrstream(const char* s, streamsize n); -istrstream(char* s, streamsize n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the base class with \tcode{istream(\&sb)} -and \tcode{sb} with \tcode{strstreambuf(s, n)}. -\tcode{s} shall designate the first element of an array whose length is -\tcode{n} elements, and \tcode{n} shall be greater than zero. -\end{itemdescr} - -\rSec3[depr.istrstream.members]{Member functions} - -\indexlibrarymember{rdbuf}{istrstream}% -\begin{itemdecl} -strstreambuf* rdbuf() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{const_cast(\&sb)}. -\end{itemdescr} - -\indexlibrarymember{str}{istrstream}% -\begin{itemdecl} -char* str(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{rdbuf()->str()}. -\end{itemdescr} - -\rSec2[depr.ostrstream]{Class \tcode{ostrstream}} - -\rSec3[depr.ostrstream.general]{General} - -\indexlibraryglobal{ostrstream}% -\begin{codeblock} -namespace std { - class ostrstream : public basic_ostream { - public: - ostrstream(); - ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out); - virtual ~ostrstream(); - - strstreambuf* rdbuf() const; - void freeze(bool freezefl = true); - char* str(); - int pcount() const; - private: - strstreambuf sb; // \expos - }; -} -\end{codeblock} - -\pnum -The class -\tcode{ostrstream} -supports the writing of objects of class -\tcode{strstreambuf}. -It supplies a -\tcode{strstreambuf} -object to control the associated array object. -For the sake of exposition, the maintained data is presented here as: - -\begin{itemize} -\item -\tcode{sb}, the \tcode{strstreambuf} object. -\end{itemize} - -\rSec3[depr.ostrstream.cons]{\tcode{ostrstream} constructors} - -\indexlibraryctor{ostrstream}% -\begin{itemdecl} -ostrstream(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the base class with \tcode{ostream(\&sb)} and -\tcode{sb} with \tcode{strstreambuf()}. -\end{itemdescr} - -\indexlibraryctor{ostrstream}% -\begin{itemdecl} -ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the base class with \tcode{ostream(\&sb)}, -and \tcode{sb} with one of two constructors: - -\begin{itemize} -\item -If -\tcode{(mode \& app) == 0}, -then \tcode{s} shall designate the first element of an array of \tcode{n} elements. - -The constructor is -\tcode{strstreambuf(s, n, s)}. -\item -If -\tcode{(mode \& app) != 0}, -then \tcode{s} shall designate the first element of an array of \tcode{n} elements that -contains an \ntbs{} whose first element is designated by \tcode{s}. -\indextext{NTBS@\ntbs{}}% -The constructor is -\tcode{strstreambuf(s, n, s + std::strlen(s))}. -\begin{footnote} -The function signature -\indexlibraryglobal{strlen}% -\tcode{strlen(const char*)} -is declared in \libheaderref{cstring}. -\end{footnote} -\end{itemize} -\end{itemdescr} - -\rSec3[depr.ostrstream.members]{Member functions} - -\indexlibrarymember{rdbuf}{ostrstream}% -\begin{itemdecl} -strstreambuf* rdbuf() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{(strstreambuf*)\&sb}. -\end{itemdescr} - -\indexlibrarymember{freeze}{ostrstream}% -\begin{itemdecl} -void freeze(bool freezefl = true); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls -\tcode{rdbuf()->freeze(freezefl)}. -\end{itemdescr} - -\indexlibrarymember{str}{ostrstream}% -\begin{itemdecl} -char* str(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{rdbuf()->str()}. -\end{itemdescr} - -\indexlibrarymember{pcount}{ostrstream}% -\begin{itemdecl} -int pcount() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{rdbuf()->pcount()}. -\end{itemdescr} - -\rSec2[depr.strstream]{Class \tcode{strstream}} - -\rSec3[depr.strstream.general]{General} - -\indexlibraryglobal{strstream}% -\begin{codeblock} -namespace std { - class strstream - : public basic_iostream { - public: - // types - using char_type = char; - using int_type = char_traits::int_type; - using pos_type = char_traits::pos_type; - using off_type = char_traits::off_type; - - // constructors/destructor - strstream(); - strstream(char* s, int n, - ios_base::openmode mode = ios_base::in|ios_base::out); - virtual ~strstream(); - - // members - strstreambuf* rdbuf() const; - void freeze(bool freezefl = true); - int pcount() const; - char* str(); - - private: - strstreambuf sb; // \expos - }; -} -\end{codeblock} - -\pnum -The class -\tcode{strstream} -supports reading and writing from objects of class -\tcode{strstreambuf}. -It supplies a -\tcode{strstreambuf} -object to control the associated array object. -For the sake of exposition, the maintained data is presented here as: - -\begin{itemize} -\item -\tcode{sb}, the \tcode{strstreambuf} object. -\end{itemize} - -\rSec3[depr.strstream.cons]{\tcode{strstream} constructors} - -\indexlibraryctor{strstream}% -\begin{itemdecl} -strstream(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the base class with \tcode{iostream(\&sb)}. -\end{itemdescr} - -\indexlibraryctor{strstream}% -\begin{itemdecl} -strstream(char* s, int n, - ios_base::openmode mode = ios_base::in|ios_base::out); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the base class with \tcode{iostream(\&sb)}, -and \tcode{sb} with one of the two constructors: -\begin{itemize} -\item -If -\tcode{(mode \& app) == 0}, -then \tcode{s} shall designate the first element of an array of \tcode{n} elements. -The constructor is -\tcode{strstreambuf(s,n,s)}. -\item -If -\tcode{(mode \& app) != 0}, -then \tcode{s} shall -designate the first element of an array of \tcode{n} elements that contains -an \ntbs{} whose first element is designated by \tcode{s}. -The constructor is -\tcode{strstreambuf(s,n,s + std::strlen(s))}. -\indexlibrarydtor{strstream}% -\end{itemize} -\end{itemdescr} - -\rSec3[depr.strstream.dest]{\tcode{strstream} destructor} - -\indexlibrarydtor{strstream}% -\begin{itemdecl} -virtual ~strstream(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Destroys an object of class -\tcode{strstream}. -\end{itemdescr} - -\rSec3[depr.strstream.oper]{\tcode{strstream} operations} - -\indexlibrarymember{rdbuf}{strstream}% -\begin{itemdecl} -strstreambuf* rdbuf() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{const_cast(\&sb)}. -\end{itemdescr} - -\indexlibrarymember{freeze}{strstream}% -\begin{itemdecl} -void freeze(bool freezefl = true); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls -\tcode{rdbuf()->freeze(freezefl)}. -\end{itemdescr} - -\indexlibrarymember{str}{strstream}% -\begin{itemdecl} -char* str(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{rdbuf()->str()}. -\end{itemdescr} - -\indexlibrarymember{pcount}{strstream}% -\begin{itemdecl} -int pcount() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{rdbuf()->pcount()}. -\end{itemdescr} - -\rSec1[depr.cerrno]{Deprecated error numbers} - -\pnum -The following macros are defined in addition to those -specified in \ref{cerrno.syn}: - -\indexlibraryglobal{ENODATA}% -\indexlibraryglobal{ENOSR}% -\indexlibraryglobal{ENOSTR}% -\indexlibraryglobal{ETIME}% -\begin{codeblock} -#define ENODATA @\seebelow@ -#define ENOSR @\seebelow@ -#define ENOSTR @\seebelow@ -#define ETIME @\seebelow@ -\end{codeblock} - -\pnum -The meaning of these macros is defined by the POSIX standard. - -\pnum -The following \tcode{enum errc} enumerators are defined -in addition to those specified in \ref{system.error.syn}: - -\begin{codeblock} -no_message_available, // \tcode{ENODATA} -no_stream_resources, // \tcode{ENOSR} -not_a_stream, // \tcode{ENOSTR} -stream_timeout, // \tcode{ETIME} -\end{codeblock} - -\pnum -The value of each \tcode{enum errc} enumerator above -is the same as the value of the \libheader{cerrno} macro -shown in the above synopsis. - -\rSec1[depr.default.allocator]{The default allocator} - -\pnum -The following member is defined in addition to those -specified in \ref{default.allocator}: - -\indexlibrarymember{is_always_equal}{allocator}% -\begin{codeblock} -namespace std { - template class allocator { - public: - using is_always_equal = true_type; - }; -} -\end{codeblock} - -\rSec1[depr.mem.poly.allocator.mem]{Deprecated \tcode{polymorphic_allocator} member function} - -\pnum -The following member is declared in addition to those members -specified in \ref{mem.poly.allocator.mem}: - -\begin{codeblock} -namespace std::pmr { - template - class polymorphic_allocator { - public: - template - void destroy(T* p); - }; -} -\end{codeblock} - -\indexlibrarymember{destroy}{polymorphic_allocator}% -\begin{itemdecl} -template - void destroy(T* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -As if by \tcode{p->\~T()}. -\end{itemdescr} - -\rSec1[depr.meta.types]{Deprecated type traits} - -\pnum -The header \libheaderrefx{type_traits}{meta.type.synop} -has the following addition: - -\begin{codeblock} -namespace std { - template struct is_pod; - template constexpr bool is_pod_v = is_pod::value; - template // \seebelow - struct aligned_storage; - template // \seebelow - using @\libglobal{aligned_storage_t}@ = typename aligned_storage::type; - template - struct aligned_union; - template - using @\libglobal{aligned_union_t}@ = typename aligned_union::type; -} -\end{codeblock} - -\pnum -The behavior of a program that adds specializations for -any of the templates defined in this subclause is undefined, -unless explicitly permitted by the specification of the corresponding template. - -\pnum -\indextext{POD}% -A \term{POD class} is a class that is both a trivial class and a -standard-layout class, and has no non-static data members of type non-POD class -(or array thereof). A \term{POD type} is a scalar type, a POD class, an array -of such a type, or a cv-qualified version of one of these types. - -\indexlibraryglobal{is_pod}% -\begin{itemdecl} -template struct is_pod; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{remove_all_extents_t} shall be a complete type or \cv{} \keyword{void}. - -\pnum -\remarks -\tcode{is_pod} is a \oldconcept{UnaryTypeTrait}\iref{meta.rqmts} -with a base characteristic of \tcode{true_type} -if \tcode{T} is a POD type, -and \tcode{false_type} otherwise. - -\pnum -\begin{note} -It is unspecified whether a closure type\iref{expr.prim.lambda.closure} is a POD type. -\end{note} -\end{itemdescr} - -\indexlibraryglobal{aligned_storage}% -\begin{itemdecl} -template - struct aligned_storage; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The value of \exposid{default-alignment} is the most -stringent alignment requirement for any object type whose size -is no greater than \tcode{Len}\iref{basic.types}. - -\pnum -\mandates -\tcode{Len} is not zero. -\tcode{Align} is equal to \tcode{alignof(T)} for some type \tcode{T} or -to \exposid{default-alignment}. - -\pnum -The member typedef \tcode{type} denotes a trivial standard-layout type -suitable for use as uninitialized storage for any object -whose size is at most \tcode{Len} and -whose alignment is a divisor of \tcode{Align}. - -\pnum -\begin{note} -Uses of \tcode{aligned_storage::type} can be replaced -by an array \tcode{std::byte[Len]} declared with \tcode{alignas(Align)}. -\end{note} - -\pnum -\begin{note} -A typical implementation would define \tcode{aligned_storage} as: -\begin{codeblock} -template -struct aligned_storage { - typedef struct { - alignas(Alignment) unsigned char __data[Len]; - } type; -}; -\end{codeblock} -\end{note} - -\end{itemdescr} - -\indexlibraryglobal{aligned_union}% -\begin{itemdecl} -template - struct aligned_union; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -At least one type is provided. -Each type in the template parameter pack \tcode{Types} -is a complete object type. - -\pnum -The member typedef \tcode{type} denotes a trivial standard-layout type -suitable for use as uninitialized storage for any object -whose type is listed in \tcode{Types}; -its size shall be at least \tcode{Len}. -The static member \tcode{alignment_value} -is an integral constant of type \tcode{size_t} -whose value is the strictest alignment of all types listed in \tcode{Types}. -\end{itemdescr} - -\rSec1[depr.tuple]{Tuple} - -\pnum -The header \libheaderref{tuple} has the following additions: - -\begin{codeblock} -namespace std { - template struct tuple_size; - template struct tuple_size; - - template struct tuple_element; - template struct tuple_element; -} -\end{codeblock} - -\begin{itemdecl} -template struct tuple_size; -template struct tuple_size; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{TS} denote \tcode{tuple_size} of the cv-unqualified type \tcode{T}. -If the expression \tcode{TS::value} is well-formed -when treated as an unevaluated operand\iref{term.unevaluated.operand}, -then specializations of each of the two templates meet -the \oldconcept{TransformationTrait} requirements with a base characteristic of -\tcode{integral_constant}. -Otherwise, they have no member \tcode{value}. - -\pnum -Access checking is performed as if -in a context unrelated to \tcode{TS} and \tcode{T}. -Only the validity of the immediate context of the expression is considered. - -\pnum -In addition to being available via inclusion of the \libheaderref{tuple} header, -the two templates are available when any of the headers -\libheaderref{array}, -\libheaderref{ranges}, or -\libheaderref{utility} -are included. -\end{itemdescr} - -\begin{itemdecl} -template struct tuple_element; -template struct tuple_element; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{TE} denote \tcode{tuple_element_t} -of the cv-unqualified type \tcode{T}. -Then specializations of each of the two templates meet -the \oldconcept{TransformationTrait} requirements -with a member typedef \tcode{type} that names the following type: -\begin{itemize} -\item for the first specialization, \tcode{add_volatile_t}, and -\item for the second specialization, \tcode{add_cv_t}. -\end{itemize} - -\pnum -In addition to being available via inclusion of the \libheaderref{tuple} header, -the two templates are available when any of the headers -\libheaderref{array}, -\libheaderref{ranges}, or -\libheaderref{utility} -are included. -\end{itemdescr} - -\rSec1[depr.variant]{Variant} - -\pnum -The header \libheaderref{variant} has the following additions: - -\begin{codeblock} -namespace std { - template struct variant_size; - template struct variant_size; - - template struct variant_alternative; - template struct variant_alternative; -} -\end{codeblock} - -\begin{itemdecl} -template struct variant_size; -template struct variant_size; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{VS} denote \tcode{variant_size} -of the cv-unqualified type \tcode{T}. -Then specializations of each of the two templates meet -the \oldconcept{UnaryTypeTrait} requirements -with a base characteristic of \tcode{integral_constant}. -\end{itemdescr} - -\begin{itemdecl} -template struct variant_alternative; -template struct variant_alternative; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{VA} denote \tcode{variant_alternative} -of the cv-unqualified type \tcode{T}. -Then specializations of each of the two templates meet -the \oldconcept{TransformationTrait} requirements -with a member typedef \tcode{type} that names the following type: -\begin{itemize} -\item for the first specialization, \tcode{add_volatile_t}, and -\item for the second specialization, \tcode{add_cv_t}. -\end{itemize} -\end{itemdescr} - -\rSec1[depr.iterator]{Deprecated \tcode{iterator} class template} - -\pnum -The header \libheaderrefx{iterator}{iterator.synopsis} has the following addition: - -\indexlibraryglobal{iterator}% -\begin{codeblock} -namespace std { - template - struct iterator { - using iterator_category = Category; - using value_type = T; - using difference_type = Distance; - using pointer = Pointer; - using reference = Reference; - }; -} -\end{codeblock} - -\pnum -The -\tcode{iterator} -template may be used as a base class to ease the definition of required types -for new iterators. - -\pnum -\begin{note} -If the new iterator type is a class template, then these aliases -will not be visible from within the iterator class's template definition, but -only to callers of that class. -\end{note} - -\pnum -\begin{example} -If a \Cpp{} program wants to define a bidirectional iterator for some data -structure containing \tcode{double} and such that it works on a large memory -model of the implementation, it can do so with: - -\begin{codeblock} -class MyIterator : - public iterator { - // code implementing \tcode{++}, etc. -}; -\end{codeblock} -\end{example} - -\rSec1[depr.move.iter.elem]{Deprecated \tcode{move_iterator} access} - -\pnum -The following member is declared in addition to those members -specified in \ref{move.iter.elem}: - -\begin{codeblock} -namespace std { - template - class move_iterator { - public: - constexpr pointer operator->() const; - }; -} -\end{codeblock} - -\indexlibrarymember{operator->}{move_iterator}% -\begin{itemdecl} -constexpr pointer operator->() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{current}. -\end{itemdescr} - -\rSec1[depr.util.smartptr.shared.atomic]{Deprecated \tcode{shared_ptr} atomic access} - -\pnum -The header \libheaderref{memory} has the following additions: - -\indexlibraryglobal{shared_ptr}% -\begin{codeblock} -namespace std { - template - bool atomic_is_lock_free(const shared_ptr* p); - - template - shared_ptr atomic_load(const shared_ptr* p); - template - shared_ptr atomic_load_explicit(const shared_ptr* p, memory_order mo); - - template - void atomic_store(shared_ptr* p, shared_ptr r); - template - void atomic_store_explicit(shared_ptr* p, shared_ptr r, memory_order mo); - - template - shared_ptr atomic_exchange(shared_ptr* p, shared_ptr r); - template - shared_ptr atomic_exchange_explicit(shared_ptr* p, shared_ptr r, memory_order mo); - - template - bool atomic_compare_exchange_weak(shared_ptr* p, shared_ptr* v, shared_ptr w); - template - bool atomic_compare_exchange_strong(shared_ptr* p, shared_ptr* v, shared_ptr w); - template - bool atomic_compare_exchange_weak_explicit( - shared_ptr* p, shared_ptr* v, shared_ptr w, - memory_order success, memory_order failure); - template - bool atomic_compare_exchange_strong_explicit( - shared_ptr* p, shared_ptr* v, shared_ptr w, - memory_order success, memory_order failure); -} -\end{codeblock} - -\pnum -Concurrent access to a \tcode{shared_ptr} object from multiple threads does not -introduce a data race if the access is done exclusively via the functions in -this subclause and the instance is passed as their first argument. - -\pnum -The meaning of the arguments of type \tcode{memory_order} is explained in~\ref{atomics.order}. - -\indexlibrarymember{atomic_is_lock_free}{shared_ptr}% -\begin{itemdecl} -template bool atomic_is_lock_free(const shared_ptr* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null. - -\pnum -\returns -\tcode{true} if atomic access to \tcode{*p} is lock-free, \tcode{false} otherwise. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_load}{shared_ptr}% -\begin{itemdecl} -template shared_ptr atomic_load(const shared_ptr* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null. - -\pnum -\returns -\tcode{atomic_load_explicit(p, memory_order::seq_cst)}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_load_explicit}{shared_ptr}% -\begin{itemdecl} -template shared_ptr atomic_load_explicit(const shared_ptr* p, memory_order mo); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null. -\tcode{mo} is neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\returns -\tcode{*p}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_store}{shared_ptr}% -\begin{itemdecl} -template void atomic_store(shared_ptr* p, shared_ptr r); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null. - -\pnum -\effects -As if by \tcode{atomic_store_explicit(p, r, memory_order::seq_cst)}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_store_explicit}{shared_ptr}% -\begin{itemdecl} -template void atomic_store_explicit(shared_ptr* p, shared_ptr r, memory_order mo); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null. -\tcode{mo} is neither \tcode{memory_order::acquire} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -As if by \tcode{p->swap(r)}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_exchange}{shared_ptr}% -\begin{itemdecl} -template shared_ptr atomic_exchange(shared_ptr* p, shared_ptr r); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null. - -\pnum -\returns -\tcode{atomic_exchange_explicit(p, r, memory_order::seq_cst)}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_exchange_explicit}{shared_ptr}% -\begin{itemdecl} -template - shared_ptr atomic_exchange_explicit(shared_ptr* p, shared_ptr r, memory_order mo); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null. - -\pnum -\effects -As if by \tcode{p->swap(r)}. - -\pnum -\returns -The previous value of \tcode{*p}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_compare_exchange_weak}{shared_ptr}% -\begin{itemdecl} -template - bool atomic_compare_exchange_weak(shared_ptr* p, shared_ptr* v, shared_ptr w); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null and \tcode{v} is not null. - -\pnum -\returns -\begin{codeblock} -atomic_compare_exchange_weak_explicit(p, v, w, memory_order::seq_cst, memory_order::seq_cst) -\end{codeblock} - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{atomic_compare_exchange_strong}{shared_ptr}% -\begin{itemdecl} -template - bool atomic_compare_exchange_strong(shared_ptr* p, shared_ptr* v, shared_ptr w); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\begin{codeblock} -atomic_compare_exchange_strong_explicit(p, v, w, memory_order::seq_cst, - memory_order::seq_cst) -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{atomic_compare_exchange_weak_explicit}{shared_ptr}% -\indexlibrarymember{atomic_compare_exchange_strong_explicit}{shared_ptr}% -\begin{itemdecl} -template - bool atomic_compare_exchange_weak_explicit( - shared_ptr* p, shared_ptr* v, shared_ptr w, - memory_order success, memory_order failure); -template - bool atomic_compare_exchange_strong_explicit( - shared_ptr* p, shared_ptr* v, shared_ptr w, - memory_order success, memory_order failure); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} is not null and \tcode{v} is not null. -The \tcode{failure} argument is neither \tcode{memory_order::release} nor -\tcode{memory_order::acq_rel}. - -\pnum -\effects -If \tcode{*p} is equivalent to \tcode{*v}, assigns \tcode{w} to -\tcode{*p} and has synchronization semantics corresponding to the value of -\tcode{success}, otherwise assigns \tcode{*p} to \tcode{*v} and has -synchronization semantics corresponding to the value of \tcode{failure}. - -\pnum -\returns -\tcode{true} if \tcode{*p} was equivalent to \tcode{*v}, \tcode{false} otherwise. - -\pnum -\throws -Nothing. - -\pnum -\remarks -Two \tcode{shared_ptr} objects are equivalent if they store the same -pointer value and share ownership. -The weak form may fail spuriously. See~\ref{atomics.types.operations}. -\end{itemdescr} - -\rSec1[depr.string.capacity]{Deprecated \tcode{basic_string} capacity} - -\pnum -The following member is declared in addition to those members specified -in \ref{string.capacity}: - -\indexlibraryglobal{basic_string}% -\begin{codeblock} -namespace std { - template, - class Allocator = allocator> - class basic_string { - public: - void reserve(); - }; -} -\end{codeblock} - -\indexlibrarymember{reserve}{basic_string}% -\begin{itemdecl} -void reserve(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -After this call, \tcode{capacity()} has an unspecified value -greater than or equal to \tcode{size()}. -\begin{note} -This is a non-binding shrink to fit request. -\end{note} -\end{itemdescr} - -\rSec1[depr.format]{Deprecated formatting} - -\rSec2[depr.format.syn]{Header \tcode{} synopsis} - -\pnum -The header \libheaderref{format}{format.syn} has the following additions: - -\begin{codeblock} -namespace std { - template - decltype(auto) visit_format_arg(Visitor&& vis, basic_format_arg arg); -} -\end{codeblock} - -\rSec2[depr.format.arg]{Formatting arguments} - -\indexlibraryglobal{visit_format_arg}% -\begin{itemdecl} -template - decltype(auto) visit_format_arg(Visitor&& vis, basic_format_arg arg); -\end{itemdecl} +\mandates +At least one type is provided. +Each type in the template parameter pack \tcode{Types} +is a complete object type. -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return visit(std::forward(vis), arg.value);} +The member typedef \tcode{type} denotes a trivial standard-layout type +suitable for use as uninitialized storage for any object +whose type is listed in \tcode{Types}; +its size shall be at least \tcode{Len}. +The static member \tcode{alignment_value} +is an integral constant of type \tcode{size_t} +whose value is the strictest alignment of all types listed in \tcode{Types}. \end{itemdescr} -\rSec1[depr.locale.stdcvt]{Deprecated standard code conversion facets} - -\rSec2[depr.locale.stdcvt.general]{General} - -\pnum -The header \libheaderdef{codecvt} provides -code conversion facets for various character encodings. - -\rSec2[depr.codecvt.syn]{Header \tcode{} synopsis} - -\indexlibraryglobal{codecvt_mode}% -\indexlibraryglobal{codecvt_utf8}% -\indexlibraryglobal{codecvt_utf16}% -\indexlibraryglobal{codecvt_utf8_utf16}% -\begin{codeblock} -namespace std { - enum codecvt_mode { - consume_header = 4, - generate_header = 2, - little_endian = 1 - }; - - template - class codecvt_utf8 : public codecvt { - public: - explicit codecvt_utf8(size_t refs = 0); - ~codecvt_utf8(); - }; - - template - class codecvt_utf16 : public codecvt { - public: - explicit codecvt_utf16(size_t refs = 0); - ~codecvt_utf16(); - }; - - template - class codecvt_utf8_utf16 : public codecvt { - public: - explicit codecvt_utf8_utf16(size_t refs = 0); - ~codecvt_utf8_utf16(); - }; -} -\end{codeblock} - -\rSec2[depr.locale.stdcvt.req]{Requirements} - -\pnum -For each of the three code conversion facets \tcode{codecvt_utf8}, -\tcode{codecvt_utf16}, and \tcode{codecvt_utf8_utf16}: -\begin{itemize} -\item - \tcode{Elem} is the wide-character type, such as - \keyword{wchar_t}, \keyword{char16_t}, or \keyword{char32_t}. -\item - \tcode{Maxcode} is the largest wide-character code that the facet - will read or write without reporting a conversion error. -\item - If \tcode{(Mode \& consume_header)}, the facet shall consume an - initial header sequence, if present, when reading a multibyte sequence - to determine the endianness of the subsequent multibyte sequence to be read. -\item - If \tcode{(Mode \& generate_header)}, the facet shall generate an - initial header sequence when writing a multibyte sequence to advertise - the endianness of the subsequent multibyte sequence to be written. -\item - If \tcode{(Mode \& little_endian)}, the facet shall generate a - multibyte sequence in little-endian order, - as opposed to the default big-endian order. -\item - UCS-2 is the same encoding as UTF-16, - except that it encodes scalar values in the range - \ucode{0000}--\ucode{ffff} (Basic Multilingual Plane) only. -\end{itemize} - -\pnum -\indextext{UTF-8}% -\indextext{UCS-2}% -\indextext{UTF-32}% -For the facet \tcode{codecvt_utf8}\indexlibraryglobal{codecvt_utf8}: -\begin{itemize} -\item - The facet shall convert between UTF-8 multibyte sequences - and UCS-2 or UTF-32 (depending on the size of \tcode{Elem}). -\item - Endianness shall not affect how multibyte sequences are read or written. -\item - The multibyte sequences may be written as either a text or a binary file. -\end{itemize} - -\pnum -\indextext{UTF-16}% -\indextext{UCS-2}% -\indextext{UTF-32}% -For the facet \tcode{codecvt_utf16}\indexlibraryglobal{codecvt_utf16}: -\begin{itemize} -\item - The facet shall convert between UTF-16 multibyte sequences - and UCS-2 or UTF-32 (depending on the size of \tcode{Elem}). -\item - Multibyte sequences shall be read or written - according to the \tcode{Mode} flag, as set out above. -\item - The multibyte sequences may be written only as a binary file. - Attempting to write to a text file produces undefined behavior. -\end{itemize} - -\pnum -\indextext{UTF-8}% -\indextext{UTF-16}% -For the facet \tcode{codecvt_utf8_utf16}\indexlibraryglobal{codecvt_utf8_utf16}: -\begin{itemize} -\item - The facet shall convert between UTF-8 multibyte sequences - and UTF-16 (one or two 16-bit codes) within the program. -\item - Endianness shall not affect how multibyte sequences are read or written. -\item - The multibyte sequences may be written as either a text or a binary file. -\end{itemize} - -\rSec1[depr.conversions]{Deprecated convenience conversion interfaces} - -\rSec2[depr.conversions.general]{General} - -\pnum -The header \libheaderref{locale} has the following additions: - -\begin{codeblock} -namespace std { - template, - class ByteAlloc = allocator> - class wstring_convert; - - template> - class wbuffer_convert; -} -\end{codeblock} - -\rSec2[depr.conversions.string]{Class template \tcode{wstring_convert}} +\rSec1[depr.relops]{Relational operators}% +\indexlibraryglobal{rel_ops}% \pnum -Class template \tcode{wstring_convert} performs conversions between a wide -string and a byte string. It lets you specify a code conversion facet -(like class template \tcode{codecvt}) to perform the conversions, without -affecting any streams or locales. -\begin{example} -If you want to use the code -conversion facet \tcode{codecvt_utf8} to output to \tcode{cout} a UTF-8 -multibyte sequence corresponding to a wide string, but you don't want to -alter the locale for \tcode{cout}, you can write something like: -\begin{codeblock} -std::wstring_convert> myconv; -std::string mbstring = myconv.to_bytes(L"Hello\n"); -std::cout << mbstring; -\end{codeblock} -\end{example} +The header \libheaderref{utility} has the following additions: -\indexlibraryglobal{wstring_convert}% -\indexlibrarymember{byte_string}{wstring_convert}% -\indexlibrarymember{int_type}{wstring_convert}% -\indexlibrarymember{state_type}{wstring_convert}% -\indexlibrarymember{wide_string}{wstring_convert}% \begin{codeblock} -namespace std { - template, - class ByteAlloc = allocator> - class wstring_convert { - public: - using byte_string = basic_string, ByteAlloc>; - using wide_string = basic_string, WideAlloc>; - using state_type = typename Codecvt::state_type; - using int_type = typename wide_string::traits_type::int_type; - - wstring_convert() : wstring_convert(new Codecvt) {} - explicit wstring_convert(Codecvt* pcvt); - wstring_convert(Codecvt* pcvt, state_type state); - explicit wstring_convert(const byte_string& byte_err, - const wide_string& wide_err = wide_string()); - ~wstring_convert(); - - wstring_convert(const wstring_convert&) = delete; - wstring_convert& operator=(const wstring_convert&) = delete; - - wide_string from_bytes(char byte); - wide_string from_bytes(const char* ptr); - wide_string from_bytes(const byte_string& str); - wide_string from_bytes(const char* first, const char* last); - - byte_string to_bytes(Elem wchar); - byte_string to_bytes(const Elem* wptr); - byte_string to_bytes(const wide_string& wstr); - byte_string to_bytes(const Elem* first, const Elem* last); - - size_t converted() const noexcept; - state_type state() const; - - private: - byte_string byte_err_string; // \expos - wide_string wide_err_string; // \expos - Codecvt* cvtptr; // \expos - state_type cvtstate; // \expos - size_t cvtcount; // \expos - }; +namespace std::rel_ops { + template bool operator!=(const T&, const T&); + template bool operator> (const T&, const T&); + template bool operator<=(const T&, const T&); + template bool operator>=(const T&, const T&); } \end{codeblock} \pnum -The class template describes an object that controls conversions between wide -string objects of class \tcode{basic_string, -WideAlloc>} and byte string objects of class \tcode{basic_string, ByteAlloc>}. The class template defines the types -\tcode{wide_string} and \tcode{byte_string} as synonyms for these two types. -Conversion between a sequence of \tcode{Elem} values (stored in a -\tcode{wide_string} object) and multibyte sequences (stored in a -\tcode{byte_string} object) is performed by an object of class -\tcode{Codecvt}, which meets the -requirements of the standard code-conversion facet \tcode{codecvt}. - -\pnum -An object of this class template stores: - -\begin{itemize} -\item \tcode{byte_err_string} --- a byte string to display on errors -\item \tcode{wide_err_string} --- a wide string to display on errors -\item \tcode{cvtptr} --- a pointer to the allocated conversion object -(which is freed when the \tcode{wstring_convert} object is destroyed) -\item \tcode{cvtstate} --- a conversion state object -\item \tcode{cvtcount} --- a conversion count -\end{itemize} +To avoid redundant definitions of \tcode{operator!=} out of \tcode{operator==} +and operators \tcode{>}, \tcode{<=}, and \tcode{>=} out of \tcode{operator<}, +the library provides the following: -\indexlibrarymember{converted}{wstring_convert}% +\indexlibrary{\idxcode{operator"!=}}% \begin{itemdecl} -size_t converted() const noexcept; +template bool operator!=(const T& x, const T& y); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{T} meets the \oldconcept{EqualityComparable} requirements (\tref{cpp17.equalitycomparable}). + \pnum \returns -\tcode{cvtcount}. +\tcode{!(x == y)}. \end{itemdescr} -\indexlibrarymember{from_bytes}{wstring_convert}% +\indexlibraryglobal{operator>}% \begin{itemdecl} -wide_string from_bytes(char byte); -wide_string from_bytes(const char* ptr); -wide_string from_bytes(const byte_string& str); -wide_string from_bytes(const char* first, const char* last); +template bool operator>(const T& x, const T& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -The first member function converts the single-element sequence \tcode{byte} to a -wide string. The second member function converts the null-terminated -sequence beginning at \tcode{ptr} to a wide string. The third member function -converts the sequence stored in \tcode{str} to a wide string. The fourth member -function converts the sequence defined by the range \range{first}{last} to a -wide string. - -\pnum -In all cases: - -\begin{itemize} -\item If the \tcode{cvtstate} object was not constructed with an explicit value, it -is set to its default value (the initial conversion state) before the -conversion begins. Otherwise it is left unchanged. - -\item The number of input elements successfully converted is stored in \tcode{cvtcount}. -\end{itemize} +\expects +\tcode{T} meets the \oldconcept{LessThanComparable} requirements (\tref{cpp17.lessthancomparable}). \pnum \returns -If no conversion error occurs, the member function returns the converted wide string. -Otherwise, if the object was constructed with a wide-error string, the -member function returns the wide-error string. -Otherwise, the member function throws an object of class \tcode{range_error}. +\tcode{y < x}. \end{itemdescr} -\indexlibrarymember{state}{wstring_convert}% +\indexlibrary{\idxcode{operator<=}}% \begin{itemdecl} -state_type state() const; +template bool operator<=(const T& x, const T& y); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{T} meets the \oldconcept{LessThanComparable} requirements (\tref{cpp17.lessthancomparable}). + \pnum \returns -\tcode{cvtstate}. +\tcode{!(y < x)}. \end{itemdescr} -\indexlibrarymember{to_bytes}{wstring_convert}% +\indexlibrary{\idxcode{operator>=}}% \begin{itemdecl} -byte_string to_bytes(Elem wchar); -byte_string to_bytes(const Elem* wptr); -byte_string to_bytes(const wide_string& wstr); -byte_string to_bytes(const Elem* first, const Elem* last); +template bool operator>=(const T& x, const T& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -The first member function converts the single-element sequence \tcode{wchar} to a byte string. -The second member function converts the null-terminated sequence beginning at \tcode{wptr} to -a byte string. The third member function converts the sequence stored in \tcode{wstr} to a -byte string. The fourth member function converts the sequence defined by the -range \range{first}{last} to a byte string. +\expects +\tcode{T} meets the \oldconcept{LessThanComparable} requirements (\tref{cpp17.lessthancomparable}). \pnum -In all cases: +\returns +\tcode{!(x < y)}. +\end{itemdescr} -\begin{itemize} -\item If the \tcode{cvtstate} object was not constructed with an explicit value, -it is set to its default value (the initial conversion state) before the -conversion begins. Otherwise it is left unchanged. -\item The number of input elements successfully converted is stored -in \tcode{cvtcount}. -\end{itemize} +\rSec1[depr.tuple]{Tuple} \pnum -\returns -If no conversion error occurs, the member function returns the converted byte string. -Otherwise, if the object was constructed with a byte-error string, the -member function returns the byte-error string. -Otherwise, the member function throws an object of class \tcode{range_error}. -\end{itemdescr} +The header \libheaderref{tuple} has the following additions: + +\begin{codeblock} +namespace std { + template struct tuple_size; + template struct tuple_size; + + template struct tuple_element; + template struct tuple_element; +} +\end{codeblock} -\indexlibraryctor{wstring_convert}% \begin{itemdecl} -explicit wstring_convert(Codecvt* pcvt); -wstring_convert(Codecvt* pcvt, state_type state); -explicit wstring_convert(const byte_string& byte_err, - const wide_string& wide_err = wide_string()); +template struct tuple_size; +template struct tuple_size; \end{itemdecl} \begin{itemdescr} \pnum -\expects -For the first and second constructors, \tcode{pcvt} is not null. +Let \tcode{TS} denote \tcode{tuple_size} of the cv-unqualified type \tcode{T}. +If the expression \tcode{TS::value} is well-formed +when treated as an unevaluated operand\iref{term.unevaluated.operand}, +then specializations of each of the two templates meet +the \oldconcept{TransformationTrait} requirements with a base characteristic of +\tcode{integral_constant}. +Otherwise, they have no member \tcode{value}. \pnum -\effects -The first constructor stores \tcode{pcvt} in \tcode{cvtptr} and -default values in \tcode{cvtstate}, \tcode{byte_err_string}, and -\tcode{wide_err_string}. -The second constructor stores \tcode{pcvt} in \tcode{cvtptr}, -\tcode{state} in \tcode{cvtstate}, and default values in -\tcode{byte_err_string} and \tcode{wide_err_string}; moreover the -stored state is retained between calls to \tcode{from_bytes} and -\tcode{to_bytes}. -The third constructor stores \tcode{new Codecvt} in \tcode{cvtptr}, -\tcode{state_type()} in \tcode{cvtstate}, \tcode{byte_err} -in \tcode{byte_err_string}, and \tcode{wide_err} in -\tcode{wide_err_string}. +Access checking is performed as if +in a context unrelated to \tcode{TS} and \tcode{T}. +Only the validity of the immediate context of the expression is considered. + +\pnum +In addition to being available via inclusion of the \libheaderref{tuple} header, +the two templates are available when any of the headers +\libheaderref{array}, +\libheaderref{ranges}, or +\libheaderref{utility} +are included. \end{itemdescr} -\indexlibrarydtor{wstring_convert}% \begin{itemdecl} -~wstring_convert(); +template struct tuple_element; +template struct tuple_element; \end{itemdecl} \begin{itemdescr} \pnum -\effects -\tcode{delete cvtptr}. +Let \tcode{TE} denote \tcode{tuple_element_t} +of the cv-unqualified type \tcode{T}. +Then specializations of each of the two templates meet +the \oldconcept{TransformationTrait} requirements +with a member typedef \tcode{type} that names the following type: +\begin{itemize} +\item for the first specialization, \tcode{add_volatile_t}, and +\item for the second specialization, \tcode{add_cv_t}. +\end{itemize} + +\pnum +In addition to being available via inclusion of the \libheaderref{tuple} header, +the two templates are available when any of the headers +\libheaderref{array}, +\libheaderref{ranges}, or +\libheaderref{utility} +are included. \end{itemdescr} -\rSec2[depr.conversions.buffer]{Class template \tcode{wbuffer_convert}} +\rSec1[depr.variant]{Variant} \pnum -Class template \tcode{wbuffer_convert} looks like a wide stream buffer, but -performs all its I/O through an underlying byte stream buffer that you -specify when you construct it. Like class template \tcode{wstring_convert}, it -lets you specify a code conversion facet to perform the conversions, -without affecting any streams or locales. +The header \libheaderref{variant} has the following additions: -\indexlibraryglobal{wbuffer_convert}% -\indexlibrarymember{state_type}{wbuffer_convert}% \begin{codeblock} namespace std { - template> - class wbuffer_convert : public basic_streambuf { - public: - using state_type = typename Codecvt::state_type; - - wbuffer_convert() : wbuffer_convert(nullptr) {} - explicit wbuffer_convert(streambuf* bytebuf, - Codecvt* pcvt = new Codecvt, - state_type state = state_type()); - - ~wbuffer_convert(); - - wbuffer_convert(const wbuffer_convert&) = delete; - wbuffer_convert& operator=(const wbuffer_convert&) = delete; - - streambuf* rdbuf() const; - streambuf* rdbuf(streambuf* bytebuf); - - state_type state() const; + template struct variant_size; + template struct variant_size; - private: - streambuf* bufptr; // \expos - Codecvt* cvtptr; // \expos - state_type cvtstate; // \expos - }; + template struct variant_alternative; + template struct variant_alternative; } \end{codeblock} -\pnum -The class template describes a stream buffer that controls the -transmission of elements of type \tcode{Elem}, whose character traits are -described by the class \tcode{Tr}, to and from a byte stream buffer of type -\tcode{streambuf}. Conversion between a sequence of \tcode{Elem} values and -multibyte sequences is performed by an object of class -\tcode{Codecvt}, which shall meet the requirements -of the standard code-conversion facet \tcode{codecvt}. - -\pnum -An object of this class template stores: - -\begin{itemize} -\item \tcode{bufptr} --- a pointer to its underlying byte stream buffer -\item \tcode{cvtptr} --- a pointer to the allocated conversion object -(which is freed when the \tcode{wbuffer_convert} object is destroyed) -\item \tcode{cvtstate} --- a conversion state object -\end{itemize} - -\indexlibrarymember{state}{wbuffer_convert}% \begin{itemdecl} -state_type state() const; +template struct variant_size; +template struct variant_size; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{cvtstate}. +Let \tcode{VS} denote \tcode{variant_size} +of the cv-unqualified type \tcode{T}. +Then specializations of each of the two templates meet +the \oldconcept{UnaryTypeTrait} requirements +with a base characteristic of \tcode{integral_constant}. \end{itemdescr} -\indexlibrarymember{rdbuf}{wbuffer_convert}% \begin{itemdecl} -streambuf* rdbuf() const; +template struct variant_alternative; +template struct variant_alternative; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{bufptr}. +Let \tcode{VA} denote \tcode{variant_alternative} +of the cv-unqualified type \tcode{T}. +Then specializations of each of the two templates meet +the \oldconcept{TransformationTrait} requirements +with a member typedef \tcode{type} that names the following type: +\begin{itemize} +\item for the first specialization, \tcode{add_volatile_t}, and +\item for the second specialization, \tcode{add_cv_t}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{rdbuf}{wbuffer_convert}% -\begin{itemdecl} -streambuf* rdbuf(streambuf* bytebuf); -\end{itemdecl} +\rSec1[depr.iterator]{Deprecated \tcode{iterator} class template} -\begin{itemdescr} \pnum -\effects -Stores \tcode{bytebuf} in \tcode{bufptr}. +The header \libheaderrefx{iterator}{iterator.synopsis} has the following addition: + +\indexlibraryglobal{iterator}% +\begin{codeblock} +namespace std { + template + struct iterator { + using iterator_category = Category; + using value_type = T; + using difference_type = Distance; + using pointer = Pointer; + using reference = Reference; + }; +} +\end{codeblock} \pnum -\returns -The previous value of \tcode{bufptr}. -\end{itemdescr} +The +\tcode{iterator} +template may be used as a base class to ease the definition of required types +for new iterators. -\indexlibraryctor{wbuffer_convert}% -\begin{itemdecl} -explicit wbuffer_convert( - streambuf* bytebuf, - Codecvt* pcvt = new Codecvt, - state_type state = state_type()); -\end{itemdecl} +\pnum +\begin{note} +If the new iterator type is a class template, then these aliases +will not be visible from within the iterator class's template definition, but +only to callers of that class. +\end{note} -\begin{itemdescr} \pnum -\expects -\tcode{pcvt} is not null. +\begin{example} +If a \Cpp{} program wants to define a bidirectional iterator for some data +structure containing \tcode{double} and such that it works on a large memory +model of the implementation, it can do so with: + +\begin{codeblock} +class MyIterator : + public iterator { + // code implementing \tcode{++}, etc. +}; +\end{codeblock} +\end{example} + +\rSec1[depr.move.iter.elem]{Deprecated \tcode{move_iterator} access} \pnum -\effects -The constructor constructs a stream buffer object, initializes -\tcode{bufptr} to \tcode{bytebuf}, initializes \tcode{cvtptr} -to \tcode{pcvt}, and initializes \tcode{cvtstate} to \tcode{state}. -\end{itemdescr} +The following member is declared in addition to those members +specified in \ref{move.iter.elem}: + +\begin{codeblock} +namespace std { + template + class move_iterator { + public: + constexpr pointer operator->() const; + }; +} +\end{codeblock} -\indexlibrarydtor{wbuffer_convert}% +\indexlibrarymember{operator->}{move_iterator}% \begin{itemdecl} -~wbuffer_convert(); +constexpr pointer operator->() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -\tcode{delete cvtptr}. +\returns +\tcode{current}. \end{itemdescr} \rSec1[depr.locale.category]{Deprecated locale category facets} @@ -2596,21 +700,25 @@ \pnum The \tcode{ctype} locale category includes the following facets as if they were specified -in table \tref{locale.category.facets} of \ref{locale.category}. +in \tref{locale.category.facets} of \ref{locale.category}. \begin{codeblock} codecvt codecvt +codecvt +codecvt \end{codeblock} \pnum The \tcode{ctype} locale category includes the following facets as if they were specified -in table \tref{locale.spec} of \ref{locale.category}. +in \tref{locale.spec} of \ref{locale.category}. \begin{codeblock} codecvt_byname codecvt_byname +codecvt_byname +codecvt_byname \end{codeblock} \pnum @@ -2618,11 +726,41 @@ in addition to those specified in~\ref{locale.codecvt}. \indextext{UTF-8}% \indextext{UTF-16}% -The specialization \tcode{codecvt} -converts between the UTF-16 and UTF-8 encoding forms, and +The specializations \tcode{codecvt} and +\tcode{codecvt} +convert between the UTF-16 and UTF-8 encoding forms, and \indextext{UTF-32}% -the specialization \tcode{codecvt} -converts between the UTF-32 and UTF-8 encoding forms. +the specializations \tcode{codecvt} and +\tcode{codecvt} +convert between the UTF-32 and UTF-8 encoding forms. + +\rSec1[depr.format]{Deprecated formatting} + +\rSec2[depr.format.syn]{Header \tcode{} synopsis} + +\pnum +The header \libheaderref{format} has the following additions: + +\begin{codeblock} +namespace std { + template + decltype(auto) visit_format_arg(Visitor&& vis, basic_format_arg arg); +} +\end{codeblock} + +\rSec2[depr.format.arg]{Formatting arguments} + +\indexlibraryglobal{visit_format_arg}% +\begin{itemdecl} +template + decltype(auto) visit_format_arg(Visitor&& vis, basic_format_arg arg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return visit(std::forward(vis), arg.value);} +\end{itemdescr} \rSec1[depr.fs.path.factory]{Deprecated filesystem path factory functions} @@ -2716,8 +854,11 @@ void atomic_init(volatile atomic*, typename atomic::value_type) noexcept; template void atomic_init(atomic*, typename atomic::value_type) noexcept; + template + constexpr T kill_dependency(T y) noexcept; // freestanding + inline constexpr memory_order memory_order_consume = memory_order::consume; // freestanding - #define ATOMIC_VAR_INIT(value) @\seebelow@ + #define @\libmacro{ATOMIC_VAR_INIT}@(value) @\seebelow@ } \end{codeblock} @@ -2766,13 +907,13 @@ \indexlibraryglobal{ATOMIC_VAR_INIT}% \begin{itemdecl} -#define ATOMIC_VAR_INIT(value) @\seebelow@ +#define @\libmacro{ATOMIC_VAR_INIT}@(value) @\seebelow@ \end{itemdecl} \begin{itemdescr} \pnum The macro expands to a token sequence suitable for constant initialization of -an atomic variable of static storage duration of a type that +an atomic variable with static storage duration of a type that is initialization-compatible with \tcode{value}. \begin{note} This operation possibly needs to initialize locks. @@ -2786,3 +927,25 @@ \end{codeblock} \end{example} \end{itemdescr} + +\rSec2[depr.atomics.order]{\tcode{memory_order::consume}} + +\indexlibraryglobal{memory_order}% +\indexlibrarymember{consume}{memory_order}% +\pnum +The \tcode{memory_order} enumeration contains an additional enumerator: +\begin{codeblock} +consume = 1 +\end{codeblock} +The \tcode{memory_order::consume} enumerator is allowed wherever +\tcode{memory_order::acquire} is allowed, and it has the same meaning. + +\begin{itemdecl} +template constexpr T kill_dependency(T y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{y}. +\end{itemdescr} diff --git a/source/grammar.tex b/source/grammar.tex index 8501d39453..db27a2f510 100644 --- a/source/grammar.tex +++ b/source/grammar.tex @@ -58,4 +58,4 @@ identifier \end{ncbnf} -\FlushAndPrintGrammar +\input{std-gram.ext} diff --git a/source/intro.tex b/source/intro.tex index e3858c184f..75705a2bab 100644 --- a/source/intro.tex +++ b/source/intro.tex @@ -34,27 +34,21 @@ \begin{itemize} % ISO documents in numerical order. \item ISO/IEC 2382, \doccite{Information technology --- Vocabulary} -\item ISO 8601:2004, \doccite{Data elements and interchange formats --- -Information interchange --- Representation of dates and times} +\item ISO 8601-1:2019, \doccite{Date and time --- Representations for information interchange --- Part 1: Basic rules} \item \IsoC{}, \doccite{Information technology --- Programming languages --- C} -\item ISO/IEC/IEEE 9945:2009, \doccite{Information Technology --- Portable -Operating System Interface (POSIX -\begin{footnote} +\item \IsoPosix{}, \doccite{Information Technology --- Portable Operating System Interface (POSIX\textregistered)\begin{footnote} POSIX\textregistered\ is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc. This information is given for the convenience of users of this document and does not constitute an endorsement by ISO or IEC of this product. -\end{footnote}% -)} -\item ISO/IEC/IEEE 9945:2009/Cor 1:2013, \doccite{Information Technology --- Portable -Operating System Interface (POSIX), Technical Corrigendum 1} -\item ISO/IEC/IEEE 9945:2009/Cor 2:2017, \doccite{Information Technology --- Portable -Operating System Interface (POSIX), Technical Corrigendum 2} -\item ISO/IEC/IEEE 60559:2020, \doccite{Information technology --- -Microprocessor Systems --- Floating-Point arithmetic} -\item ISO 80000-2:2009, \doccite{Quantities and units --- -Part 2: Mathematical signs and symbols -to be used in the natural sciences and technology} +\end{footnote} +Base Specifications, Issue 7} +\item \IsoPosix{}/Cor 1:2013, \doccite{Information Technology --- Portable Operating System Interface +(POSIX\textregistered) Base Specifications, Issue 7 --- Technical Corrigendum 1} +\item \IsoPosix{}/Cor 2:2017, \doccite{Information Technology --- Portable Operating System Interface +(POSIX\textregistered) Base Specifications, Issue 7 --- Technical Corrigendum 2} +\item \IsoFloatUndated{}:2020, \doccite{Information technology --- Microprocessor Systems --- Floating-Point arithmetic} +\item ISO 80000-2:2019, \doccite{Quantities and units --- Part 2: Mathematics} % Other international standards. \item Ecma International, \doccite{ECMAScript \begin{footnote} @@ -77,9 +71,7 @@ \indextext{definitions|(}% For the purposes of this document, the terms and definitions -given in ISO/IEC 2382, -the terms, definitions, and symbols -given in ISO 80000-2:2009, +given in ISO/IEC 2382, ISO 80000-2:2019, and the following apply. \pnum @@ -97,10 +89,10 @@ read or modify the value of an object \begin{defnote} -Only glvalues of scalar type can be used to access objects. +Only glvalues of scalar type\iref{basic.types.general} can be used to access objects. Reads of scalar objects are described in \ref{conv.lval} and modifications of scalar objects are described in -\ref{expr.ass}, \ref{expr.post.incr}, and \ref{expr.pre.incr}. +\ref{expr.assign}, \ref{expr.post.incr}, and \ref{expr.pre.incr}. Attempts to read or modify an object of class type typically invoke a constructor\iref{class.ctor} or assignment operator\iref{class.copy.assign}; @@ -111,8 +103,9 @@ \indexdefn{argument}% \indexdefn{argument!function call expression} \definition{argument}{defns.argument} -\defncontext{function call expression} expression in the -comma-separated list bounded by the parentheses +\defncontext{function call expression} +expression or \grammarterm{braced-init-list} +in the comma-separated list bounded by the parentheses \indexdefn{argument}% \indexdefn{argument!function-like macro}% @@ -180,7 +173,7 @@ \defncontext{library} \indexdefn{type!character container}% class or a type used to -represent a character +represent a \termref{defns.character}{character}{} \begin{defnote} It is used for one of the template parameters of \tcode{char_traits} @@ -190,13 +183,13 @@ \definition{collating element}{defns.regex.collating.element} \indexdefn{collating element}% -sequence of one or more characters within the +sequence of one or more \termref{defns.character}{character}{s} within the current locale that collate as if they were a single character \definition{component}{defns.component} \defncontext{library} \indexdefn{component}% -group of library entities directly related as members, parameters, or +group of library entities directly related as members, \termref{defns.parameter}{parameter}{s}, or return types \begin{defnote} @@ -214,6 +207,11 @@ constructs that it does not support. \end{defnote} +\definition{constant evaluation}{defns.const.eval} +\indexdefn{constant evaluation}% +evaluation that is performed as part of evaluating an expression +as a core constant expression\iref{expr.const} + \definition{constant subexpression}{defns.const.subexpr} \indexdefn{constant subexpression}% expression whose evaluation as subexpression of a @@ -226,13 +224,13 @@ \indexdefn{deadlock}% situation wherein one or more threads are unable to continue execution because each is -blocked waiting for one or more of the others to satisfy some condition +\termref{defns.block}{block}{ed} waiting for one or more of the others to satisfy some condition \definition{default behavior}{defns.default.behavior.impl} \indexdefn{behavior!default}% \defncontext{library implementation} specific behavior provided by the implementation, -within the scope of the required behavior +within the scope of the \termref{defns.required.behavior}{required behavior}{} \indexdefn{message!diagnostic}% \definition{diagnostic message}{defns.diagnostic} @@ -254,7 +252,18 @@ \indexdefn{type!dynamic}% \definition{dynamic type}{defns.dynamic.type.prvalue} -\defncontext{prvalue} static type of the prvalue expression +\defncontext{prvalue} \termref{defns.static.type}{static type}{} of the prvalue expression + +\indexdefn{behavior!erroneous}% +\definition{erroneous behavior}{defns.erroneous} +well-defined behavior that the implementation is recommended to diagnose +\begin{defnote} +Erroneous behavior is always the consequence of incorrect program code. +Implementations are allowed, but not required, +to diagnose it\iref{intro.compliance.general}. +Evaluation of a constant expression\iref{expr.const} +never exhibits behavior specified as erroneous in \ref{intro} through \ref{\lastcorechapter}. +\end{defnote} \definition{expression-equivalent}{defns.expression.equivalent} \defncontext{library} @@ -265,7 +274,7 @@ are all not potentially-throwing, and either -are all constant subexpressions or +are all \termref{defns.const.subexpr}{constant subexpression}{s} or are all not constant subexpressions \begin{example} @@ -283,14 +292,14 @@ \defncontext{regular expression} \indexdefn{finite state machine}% unspecified data structure that is used to -represent a regular expression, and which permits efficient matches +represent a \termref{defns.regex.regular.expression}{regular expression}{}, and which permits efficient matches against the regular expression to be obtained \definition{format specifier}{defns.regex.format.specifier} \defncontext{regular expression} \indexdefn{format specifier}% -sequence of one or more characters that is to be -replaced with some part of a regular expression match +sequence of one or more \termref{defns.character}{character}{s} that is expected to be +replaced with some part of a \termref{defns.regex.regular.expression}{regular expression}{} match \definition{handler function}{defns.handler} \defncontext{library} @@ -300,7 +309,7 @@ \begin{defnote} A \Cpp{} program may designate a handler function at various points in its execution by supplying a pointer to the function when calling any of the library functions that install -handler functions\iref{support}. +handler functions (see \ref{support}). \end{defnote} \indexdefn{program!ill-formed}% @@ -309,7 +318,7 @@ \indexdefn{behavior!implementation-defined}% \definition{implementation-defined behavior}{defns.impl.defined} -behavior, for a well-formed program construct and correct data, that +behavior, for a \termref{defns.well.formed}{well-formed program}{} construct and correct data, that depends on the implementation and that each implementation documents \definition{implementation-defined strict total order over pointers} @@ -319,7 +328,7 @@ \impldef{strict total order over pointer values} strict total ordering over all pointer values such that the ordering is consistent with the partial order -imposed by the builtin operators +imposed by the built-in operators \tcode{<}, \tcode{>}, \tcode{<=}, \tcode{>=}, and \tcode{<=>} \indexdefn{limits!implementation}% @@ -335,7 +344,7 @@ \defncontext{regular expression} \indexdefn{matched}% \indexdefn{regular expression!matched}% -condition when a sequence of zero or more characters +condition when a sequence of zero or more \termref{defns.character}{character}{s} correspond to a sequence of characters defined by the pattern \definition{modifier function}{defns.modifier} @@ -366,7 +375,7 @@ \indexdefn{NTCTS}% \indexdefn{string!null-terminated character type}% sequence of values that have -character type +\termref{defns.character}{character}{} type that precede the terminating null character type value \tcode{charT()} @@ -406,10 +415,10 @@ \definition{primary equivalence class}{defns.regex.primary.equivalence.class} \defncontext{regular expression} \indexdefn{primary equivalence class}% -set of one or more characters which +set of one or more \termref{defns.character}{character}{s} which share the same primary sort key: that is the sort key weighting that depends only upon character shape, and not accents, case, or -locale specific tailorings +locale-specific tailorings \definition{program-defined specialization}{defns.prog.def.spec} \defncontext{library} @@ -425,7 +434,7 @@ that is not part of the \Cpp{} standard library and not defined by the implementation, or a closure type of a non-implementation-provided lambda expression, -or an instantiation of a program-defined specialization +or an instantiation of a \termref{defns.prog.def.spec}{program-defined specialization}{} \begin{defnote} Types defined by the implementation include @@ -462,7 +471,7 @@ \definition{regular expression}{defns.regex.regular.expression} pattern that selects specific strings -from a set of character strings +from a set of \termref{defns.character}{character}{} strings \definition{replacement function}{defns.replacement} \defncontext{library} @@ -479,7 +488,8 @@ \definition{required behavior}{defns.required.behavior} \defncontext{library} \indexdefn{behavior!required}% -description of replacement function and handler function semantics +description of \termref{defns.replacement}{replacement function}{} +and \termref{defns.handler}{handler function}{} semantics applicable to both the behavior provided by the implementation and the behavior of any such function definition in the program @@ -500,6 +510,23 @@ \indextext{undefined} \end{defnote} +\definition{runtime-undefined behavior}{defns.undefined.runtime} +\indexdefn{behavior!runtime-undefined}% +behavior that is undefined except when it occurs during constant evaluation + +\begin{defnote} +During constant evaluation, +\begin{itemize} +\item +it is +\impldef{whether runtime-undefined behavior results in the expression being deemed non-constant} +whether runtime-undefined behavior results in the expression being deemed non-constant +(as specified in~\ref{expr.const}) and +\item +runtime-undefined behavior has no other effect. +\end{itemize} +\end{defnote} + \indexdefn{signature}% \definition{signature}{defns.signature} \defncontext{function} @@ -528,7 +555,7 @@ parameter-type-list, enclosing namespace, return type, -signature of the \grammarterm{template-head}, +\termref{defns.signature.template.head}{signature}{} of the \grammarterm{template-head}, and trailing \grammarterm{requires-clause} (if any) @@ -539,14 +566,14 @@ parameter-type-list, return type, enclosing class, -signature of the \grammarterm{template-head}, +\termref{defns.signature.template.head}{signature}{} of the \grammarterm{template-head}, and trailing \grammarterm{requires-clause} (if any) \indexdefn{signature}% \definition{signature}{defns.signature.spec} -\defncontext{function template specialization} signature of the template of which it is a specialization -and its template arguments (whether explicitly specified or deduced) +\defncontext{function template specialization} \termref{defns.signature.templ}{signature}{} of the template of which it is a specialization +and its template \termref{defns.argument.templ}{argument}{s} (whether explicitly specified or deduced) \indexdefn{signature}% \definition{signature}{defns.signature.member} @@ -568,20 +595,20 @@ \cv-qualifiers (if any), \grammarterm{ref-qualifier} (if any), return type (if any), -signature of the \grammarterm{template-head}, +\termref{defns.signature.template.head}{signature}{} of the \grammarterm{template-head}, and trailing \grammarterm{requires-clause} (if any) \indexdefn{signature}% \definition{signature}{defns.signature.member.spec} -\defncontext{class member function template specialization} signature of the member function template +\defncontext{class member function template specialization} \termref{defns.signature.member.templ}{signature}{} of the member function template of which it is a specialization and its template arguments (whether explicitly specified or deduced) \indexdefn{signature}% \definition{signature}{defns.signature.template.head} \defncontext{\grammarterm{template-head}} -template parameter list, -excluding template parameter names and default arguments, +template \termref{defns.parameter.templ}{parameter}{} list, +excluding template parameter names and default \termref{defns.argument.templ}{argument}{s}, and \grammarterm{requires-clause} (if any) @@ -610,7 +637,7 @@ \definition{sub-expression}{defns.regex.subexpression} \defncontext{regular expression} \indexdefn{sub-expression!regular expression}% -subset of a regular expression that has +subset of a \termref{defns.regex.regular.expression}{regular expression}{} that has been marked by parentheses \definition{traits class}{defns.traits} @@ -621,7 +648,7 @@ \indexdefn{unblock}% \definition{unblock}{defns.unblock} -satisfy a condition that one or more blocked threads of execution are waiting for +satisfy a condition that one or more \termref{defns.block}{blocked}{} threads of execution are waiting for \indexdefn{behavior!undefined}% \definition{undefined behavior}{defns.undefined} @@ -631,21 +658,21 @@ \begin{defnote} Undefined behavior may be expected when this document omits any explicit -definition of behavior or when a program uses an erroneous construct or erroneous data. +definition of behavior or when a program uses an incorrect construct or invalid data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a -diagnostic message), to terminating a translation or execution (with the -issuance of a diagnostic message). Many erroneous program constructs do +\termref{defns.diagnostic}{diagnostic message}{}), to terminating a translation or execution (with the +issuance of a diagnostic message). Many incorrect program constructs do not engender undefined behavior; they are required to be diagnosed. Evaluation of a constant expression\iref{expr.const} never exhibits behavior explicitly -specified as undefined in \ref{intro} through \ref{cpp}. +specified as undefined in \ref{intro} through \ref{\lastcorechapter}. \end{defnote} \indexdefn{behavior!unspecified}% \definition{unspecified behavior}{defns.unspecified} -behavior, for a well-formed program construct and correct data, that +behavior, for a \termref{defns.well.formed}{well-formed program}{} construct and correct data, that depends on the implementation \begin{defnote} @@ -718,25 +745,43 @@ \begin{itemize} \item If a program contains no violations of the rules in -\ref{lex} through \ref{\lastlibchapter} and \ref{depr}, -a conforming implementation shall, -within its resource limits as described in \ref{implimits}, -accept and correctly execute +\ref{lex} through \ref{\lastlibchapter} as well as those specified in \ref{depr}, +a conforming implementation shall accept and correctly execute \begin{footnote} -``Correct execution'' can include undefined behavior, depending on +``Correct execution'' can include undefined behavior +and erroneous behavior, depending on the data being processed; see \ref{intro.defs} and~\ref{intro.execution}. \end{footnote} -that program. +that program, +except when the implementation's limitations (see below) are exceeded. \item \indextext{behavior!undefined}% If a program contains a violation of a rule for which no diagnostic is required, this document places no requirement on implementations with respect to that program. + \item \indextext{message!diagnostic}% -Otherwise, if a program contains a violation of any diagnosable rule or an occurrence +\indextext{contract evaluation semantics!checking}% +\indextext{contract evaluation semantics!terminating}% +Otherwise, if a program contains +\begin{itemize} +\item +a violation of any diagnosable rule, +\item +a preprocessing translation unit with +a \tcode{\#warning} preprocessing directive\iref{cpp.error}, +\item +an occurrence of a construct described in this document as ``conditionally-supported'' when -the implementation does not support that construct, a conforming implementation +the implementation does not support that construct, or +\item +a contract assertion\iref{basic.contract.eval} +evaluated with a checking semantic +in a manifestly constant-evaluated context \iref{expr.const} +resulting in a contract violation, +\end{itemize} +a conforming implementation shall issue at least one diagnostic message. \end{itemize} \begin{note} @@ -746,18 +791,18 @@ see~\ref{temp.deduct}. \end{note} Furthermore, a conforming implementation +shall not accept \begin{itemize} \item -shall not accept a preprocessing translation unit containing +a preprocessing translation unit containing a \tcode{\#error} preprocessing directive\iref{cpp.error}, \item -shall issue at least one diagnostic message for -each \tcode{\#warning} or \tcode{\#error} preprocessing directive -not following a \tcode{\#error} preprocessing directive in -a preprocessing translation unit, and +a translation unit with +a \grammarterm{static_assert-declaration} that fails\iref{dcl.pre}, or \item -shall not accept a translation unit with -a \grammarterm{static_assert-declaration} that fails\iref{dcl.pre}. +a contract assertion evaluated with a terminating semantic\iref{basic.contract.eval} +in a manifestly constant-evaluated context\iref{expr.const} +resulting in a contract violation. \end{itemize} \pnum @@ -788,7 +833,8 @@ \indextext{conformance requirements!library|)} \pnum -Two kinds of implementations are defined: a \defnadj{hosted}{implementation} and a +An implementation is either a +\defnadj{hosted}{implementation} or a \defnadj{freestanding}{implementation}. A freestanding implementation is one in which execution may take place without the benefit of @@ -797,9 +843,25 @@ supports all the facilities described in this document, while a freestanding implementation supports the entire \Cpp{} language -described in \ref{lex} through \ref{cpp} and +described in \ref{lex} through \ref{\lastcorechapter} and the subset of the library facilities described in \ref{compliance}. +\pnum +It is +\impldef{whether the implementation is a hardened implementation} +whether the implementation is a +\defnadj{hardened}{implementation}. +If it is a hardened implementation, +violating a hardened precondition +results in a contract violation\iref{structure.specifications}. + +\pnum +An implementation is encouraged to document its limitations in +the size or complexity of the programs it can successfully process, +if possible and where known. +\ref{implimits} lists some quantities that can be subject to limitations and +a potential minimum supported value for each quantity. + \pnum A conforming implementation may have extensions (including additional library functions), provided they do not alter the @@ -849,7 +911,7 @@ \pnum \indextext{behavior!implementation-defined}% Certain aspects and operations of the abstract machine are described in this -document as implementation-defined (for example, +document as implementation-defined behavior (for example, \tcode{sizeof(int)}). These constitute the parameters of the abstract machine. Each implementation shall include documentation describing its characteristics and behavior in these respects. @@ -865,7 +927,7 @@ \pnum \indextext{behavior!unspecified}% Certain other aspects and operations of the abstract machine are -described in this document as unspecified (for example, +described in this document as unspecified behavior (for example, order of evaluation of arguments in a function call\iref{expr.call}). Where possible, this document defines a set of allowable behaviors. These @@ -876,45 +938,84 @@ \pnum \indextext{behavior!undefined}% Certain other operations are described in this document as -undefined (for example, the effect of +undefined behavior (for example, the effect of attempting to modify a const object). + +\pnum +Certain events in the execution of a program +are termed \defnadj{observable}{checkpoints}. \begin{note} -This document imposes no requirements on the -behavior of programs that contain undefined behavior. +A call to \tcode{std::observable}\iref{utility.undefined} +is an observable checkpoint, +as are certain parts of +the evaluation of contract assertions\iref{basic.contract}. \end{note} \pnum \indextext{program!well-formed}% \indextext{behavior!observable}% +The \defnadj{defined}{prefix} of an execution +comprises the operations $O$ +for which for every undefined operation $U$ +there is an observable checkpoint $C$ +such that $O$ happens before $C$ and +$C$ happens before $U$. + +\begin{note} +The undefined behavior that arises from a data race\iref{intro.races} +occurs on all participating threads. +\end{note} + A conforming implementation executing a well-formed program shall -produce the same observable behavior as one of the possible executions -of the corresponding instance of the abstract machine with the +produce the observable behavior +of the defined prefix +of one of the possible executions +of the corresponding instance +of the abstract machine with the same program and the same input. \indextext{behavior!undefined}% -However, if any such execution contains an undefined operation, this document places no -requirement on the implementation executing that program with that input -(not even with regard to operations preceding the first undefined -operation). +If the selected execution contains an undefined operation, +the implementation executing that program with that input +may produce arbitrary additional observable behavior afterwards. +If the execution contains an operation specified as having erroneous behavior, +the implementation is permitted to issue a diagnostic and +is permitted to terminate the execution +at an unspecified time after that operation. + +\pnum +\recommended +An implementation should issue a diagnostic when such an operation is executed. +\begin{note} +An implementation can issue a diagnostic +if it can determine that erroneous behavior is reachable +under an implementation-specific set of assumptions about the program behavior, +which can result in false positives. +\end{note} \pnum \indextext{conformance requirements}% -The least requirements on a conforming implementation are: +The following specify the +\defnadj{observable}{behavior} +of the program: \begin{itemize} \item Accesses through volatile glvalues are evaluated strictly according to the rules of the abstract machine. \item -At program termination, all data written into files shall be -identical to one of the possible results that execution of the program -according to the abstract semantics would have produced. +Data is delivered to the host environment to be written into files (\xrefc{7.21.3}). + +\begin{note} +Delivering such data +is followed by an observable checkpoint\iref{cstdio.syn}. +Not all host environments provide access to file contents before program termination. +\end{note} + \item The input and output dynamics of interactive devices shall take place in such a fashion that prompting output is actually delivered before a program waits for input. What constitutes an interactive device is \impldef{interactive device}. \end{itemize} -These collectively are referred to as the -\defnx{observable behavior}{behavior!observable} of the program. \begin{note} More stringent correspondences between abstract and actual semantics can be defined by each implementation. @@ -926,7 +1027,7 @@ \pnum \indextext{standard!structure of|(}% \indextext{standard!structure of}% -\ref{lex} through \ref{cpp} describe the \Cpp{} programming +\ref{lex} through \ref{\lastcorechapter} describe the \Cpp{} programming language. That description includes detailed syntactic specifications in a form described in~\ref{syntax}. For convenience, \ref{gram} repeats all such syntactic specifications. @@ -954,7 +1055,7 @@ \pnum \indextext{notation!syntax|(}% In the syntax notation used in this document, syntactic -categories are indicated by \fakegrammarterm{italic} type, and literal words +categories are indicated by \fakegrammarterm{italic, sans-serif} type, and literal words and characters in \tcode{constant} \tcode{width} type. Alternatives are listed on separate lines except in a few cases where a long set of alternatives is marked by the phrase ``one of''. If the text of an alternative is too long to fit on a line, the text is continued on subsequent lines indented from the first one. diff --git a/source/iostreams.tex b/source/iostreams.tex index 155919c60f..535596515e 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -86,7 +86,7 @@ It is used to represent the number of characters transferred in an I/O operation, or the size of I/O buffers. \begin{footnote} -Most places where \tcode{streamsize} is used would use \tcode{size_t} in ISO C, +Most places where \tcode{streamsize} is used would use \tcode{size_t} in C, or \tcode{ssize_t} in POSIX. \end{footnote} \end{itemdescr} @@ -128,8 +128,9 @@ \pnum In the classes of \ref{input.output}, a template parameter with name \tcode{charT} represents a member of the set of types containing \tcode{char}, \keyword{wchar_t}, -and any other \impldef{set of character types that iostreams templates can be instantiated for} -character types that meet the requirements for a character on which any of +and any other \impldef{set of character container types that iostreams templates can be instantiated for} +character container types\iref{defns.character.container} +that meet the requirements for a character on which any of the iostream components can be instantiated. \rSec2[iostreams.threadsafety]{Thread safety} @@ -479,6 +480,12 @@ declares objects that associate objects with the standard C streams provided for by the functions declared in \libheader{cstdio}, and includes all the headers necessary to use these objects. +The dynamic types of the stream buffers +initially associated with these objects are unspecified, +but they have the behavior specified for +\tcode{std::basic_filebuf} +or +\tcode{std::basic_filebuf}. \pnum The objects are constructed and the associations are established at some @@ -682,11 +689,15 @@ #include // see \ref{iosfwd.syn} namespace std { + // \ref{stream.types}, types using streamoff = @\impdef@; using streamsize = @\impdef@; + // \ref{fpos}, class template \tcode{fpos} template class fpos; + // \ref{ios.base}, class \tcode{ios_base} class ios_base; + // \ref{ios}, class template \tcode{basic_ios} template> class basic_ios; @@ -729,8 +740,8 @@ ios_base& defaultfloat(ios_base& str); // \ref{error.reporting}, error reporting - enum class io_errc { - stream = 1 + enum class @\libglobal{io_errc}@ { + @\libmember{stream}{io_errc}@ = 1 }; template<> struct is_error_code_enum : public true_type { }; @@ -826,7 +837,7 @@ virtual ~ios_base(); // \ref{ios.base.callback}, callbacks - enum event { erase_event, imbue_event, copyfmt_event }; + enum @\libmember{event}{ios_base}@ { erase_event, imbue_event, copyfmt_event }; using event_callback = void (*)(event, ios_base&, int idx); void register_callback(event_callback fn, int idx); @@ -839,9 +850,9 @@ ios_base(); private: - static int index; // \expos - long* iarray; // \expos - void** parray; // \expos + static int @\exposid{index}@; // \expos + long* @\exposid{iarray}@; // \expos + void** @\exposid{parray}@; // \expos }; } \end{codeblock} @@ -877,19 +888,19 @@ For the sake of exposition, the maintained data is presented here as: \begin{itemize} \item -\tcode{static int index}, +\tcode{static int \exposid{index}}, specifies the next available unique index for the integer or pointer arrays maintained for the private use of the program, initialized to an unspecified value; \item -\tcode{long* iarray}, +\tcode{long* \exposid{iarray}}, points to the first element of an arbitrary-length \tcode{long} array maintained for the private use of the program; \item -\tcode{void** parray}, +\tcode{void** \exposid{parray}}, points to the first element of an arbitrary-length pointer array maintained for the private use of the program. \end{itemize} @@ -917,7 +928,7 @@ to class \tcode{ios_base::failure} shown in this subclause. \begin{note} When \tcode{ios_base::failure} is a synonym for another type, -that type is required to provide a nested type \tcode{failure} +that type needs to provide a nested type \tcode{failure} to emulate the injected-class-name. \end{note} The class @@ -1127,9 +1138,6 @@ Init(const Init&) = default; ~Init(); Init& operator=(const Init&) = default; - - private: - static int init_cnt; // \expos }; } \end{codeblock} @@ -1143,17 +1151,6 @@ provided for by the functions declared in \libheaderref{cstdio}. -\pnum -For the sake of exposition, the maintained data is presented here as: -\begin{itemize} -\item -\tcode{static int init_cnt}, -counts the number of -constructor and destructor calls for class -\tcode{Init}, -initialized to zero. -\end{itemize} - \indexlibraryctor{ios_base::Init}% \begin{itemdecl} Init(); @@ -1441,7 +1438,7 @@ \begin{itemdescr} \pnum \returns -\tcode{index} +\exposid{index} \tcode{++}. \pnum @@ -1462,20 +1459,20 @@ \pnum \effects -If \tcode{iarray} is a null pointer, allocates an array of +If \exposid{iarray} is a null pointer, allocates an array of \tcode{long} of unspecified size and stores a pointer to its first element in -\tcode{iarray}. +\exposid{iarray}. The function then extends the array pointed at by -\tcode{iarray} as necessary to include the element -\tcode{iarray[idx]}. +\exposid{iarray} as necessary to include the element +\tcode{\exposid{iarray}[idx]}. Each newly allocated element of the array is initialized to zero. The reference returned is invalid after any other operation on the object. \begin{footnote} An implementation is free to implement both the integer -array pointed at by \tcode{iarray} and the pointer array pointed at by -\tcode{parray} as sparse data structures, possibly with a one-element +array pointed at by \exposid{iarray} and the pointer array pointed at by +\exposid{parray} as sparse data structures, possibly with a one-element cache for each. \end{footnote} However, the value of the storage referred to is retained, so @@ -1500,7 +1497,7 @@ \pnum \returns On success -\tcode{iarray[idx]}. +\tcode{\exposid{iarray}[idx]}. On failure, a valid \tcode{long\&} initialized to 0. @@ -1518,13 +1515,13 @@ \pnum \effects -If \tcode{parray} is a null pointer, allocates an array of +If \exposid{parray} is a null pointer, allocates an array of pointers to \keyword{void} of unspecified size and stores a pointer to its -first element in \tcode{parray}. +first element in \exposid{parray}. The function then extends the array -pointed at by \tcode{parray} as necessary to include the element -\tcode{parray[idx]}. +pointed at by \exposid{parray} as necessary to include the element +\tcode{\exposid{parray}[idx]}. Each newly allocated element of the array is initialized to a null pointer. The reference returned is invalid after any other operation on the @@ -1640,6 +1637,8 @@ \rSec2[fpos]{Class template \tcode{fpos}} +\rSec3[fpos.general]{General} + \indexlibraryglobal{fpos}% \begin{codeblock} namespace std { @@ -1650,7 +1649,7 @@ void state(stateT); private: - stateT st; // \expos + stateT @\exposid{st}@; // \expos }; } \end{codeblock} @@ -1665,7 +1664,7 @@ \begin{itemdescr} \pnum \effects -Assigns \tcode{s} to \tcode{st}. +Assigns \tcode{s} to \exposid{st}. \end{itemdescr} \indexlibrarymember{state}{fpos}% @@ -1676,7 +1675,7 @@ \begin{itemdescr} \pnum \returns -Current value of \tcode{st}. +Current value of \exposid{st}. \end{itemdescr} \rSec3[fpos.operations]{Requirements} @@ -2882,6 +2881,7 @@ \indexlibraryglobal{basic_streambuf}% \begin{codeblock} namespace std { + // \ref{streambuf}, class template \tcode{basic_streambuf} template> class basic_streambuf; using streambuf = basic_streambuf; @@ -3512,6 +3512,11 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\range{gbeg}{gnext}, \range{gbeg}{gend}, and \range{gnext}{gend} +are all valid ranges. + \pnum \ensures \tcode{gbeg == eback()}, @@ -3572,6 +3577,10 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\range{pbeg}{pend} is a valid range. + \pnum \ensures \tcode{pbeg == pbase()}, @@ -3633,7 +3642,7 @@ \begin{itemdecl} pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which - = ios_base::in | ios_base::out); + = ios_base::in | ios_base::out); \end{itemdecl} \begin{itemdescr} @@ -3655,7 +3664,7 @@ \begin{itemdecl} pos_type seekpos(pos_type sp, ios_base::openmode which - = ios_base::in | ios_base::out); + = ios_base::in | ios_base::out); \end{itemdecl} \begin{itemdescr} @@ -4137,21 +4146,25 @@ \indexheader{istream}% \begin{codeblock} namespace std { + // \ref{istream}, class template \tcode{basic_istream} template> class basic_istream; using istream = basic_istream; using wistream = basic_istream; + // \ref{iostreamclass}, class template \tcode{basic_iostream} template> class basic_iostream; using iostream = basic_iostream; using wiostream = basic_iostream; + // \ref{istream.manip}, standard \tcode{basic_istream} manipulators template basic_istream& ws(basic_istream& is); + // \ref{istream.rvalue}, rvalue stream extraction template Istream&& operator>>(Istream&& is, T&& x); } @@ -4167,12 +4180,14 @@ \indexheader{ostream}% \begin{codeblock} namespace std { + // \ref{ostream}, class template \tcode{basic_ostream} template> class basic_ostream; using ostream = basic_ostream; using wostream = basic_ostream; + // \ref{ostream.manip}, standard \tcode{basic_ostream} manipulators template basic_ostream& endl(basic_ostream& os); template @@ -4187,6 +4202,7 @@ template basic_ostream& flush_emit(basic_ostream& os); + // \ref{ostream.rvalue}, rvalue stream insertion template Ostream&& operator<<(Ostream&& os, const T& x); @@ -4195,6 +4211,7 @@ void print(ostream& os, format_string fmt, Args&&... args); template void println(ostream& os, format_string fmt, Args&&... args); + void println(ostream& os); void vprint_unicode(ostream& os, string_view fmt, format_args args); void vprint_nonunicode(ostream& os, string_view fmt, format_args args); @@ -4211,17 +4228,21 @@ \indexheader{iomanip}% \begin{codeblock} namespace std { + // \ref{std.manip}, standard manipulators @\unspec@ resetiosflags(ios_base::fmtflags mask); @\unspec@ setiosflags (ios_base::fmtflags mask); @\unspec@ setbase(int base); template @\unspec@ setfill(charT c); @\unspec@ setprecision(int n); @\unspec@ setw(int n); + + // \ref{ext.manip}, extended manipulators template @\unspec@ get_money(moneyT& mon, bool intl = false); template @\unspec@ put_money(const moneyT& mon, bool intl = false); template @\unspec@ get_time(tm* tmb, const charT* fmt); template @\unspec@ put_time(const tm* tmb, const charT* fmt); + // \ref{quoted.manip}, quoted manipulators template @\unspec@ quoted(const charT* s, charT delim = charT('"'), charT escape = charT('\\')); @@ -4252,14 +4273,18 @@ template void println(format_string fmt, Args&&... args); + void println(); template void println(FILE* stream, format_string fmt, Args&&... args); + void println(FILE* stream); void vprint_unicode(string_view fmt, format_args args); void vprint_unicode(FILE* stream, string_view fmt, format_args args); + void vprint_unicode_buffered(FILE* stream, string_view fmt, format_args args); void vprint_nonunicode(string_view fmt, format_args args); void vprint_nonunicode(FILE* stream, string_view fmt, format_args args); + void vprint_nonunicode_buffered(FILE* stream, string_view fmt, format_args args); } \end{codeblock} @@ -4488,12 +4513,12 @@ namespace std { template class basic_istream::sentry { - bool ok_; // \expos + bool @\exposid{ok_}@; // \expos public: explicit sentry(basic_istream& is, bool noskipws = false); ~sentry(); - explicit operator bool() const { return ok_; } + explicit operator bool() const { return @\exposid{ok_}@; } sentry(const sentry&) = delete; sentry& operator=(const sentry&) = delete; }; @@ -4590,9 +4615,9 @@ \tcode{is.good()} is \tcode{true}, -\tcode{ok_ != false} +\tcode{\exposid{ok_} != false} otherwise, -\tcode{ok_ == false}. +\tcode{\exposid{ok_} == false}. During preparation, the constructor may call \tcode{setstate(failbit)} (which may throw @@ -4627,7 +4652,7 @@ \begin{itemdescr} \pnum \returns -\tcode{ok_}. +\exposid{ok_}. \end{itemdescr} \rSec3[istream.formatted]{Formatted input functions} @@ -4923,7 +4948,7 @@ \pnum Characters are extracted and stored until any of the following occurs: \begin{itemize} -\item \tcode{n-1} characters are stored; +\item \tcode{n - 1} characters are stored; \item end of file occurs on the input sequence; \item letting \tcode{ct} be \tcode{use_facet>(in.getloc())}, \tcode{ct.is(ct.space, c)} is \tcode{true}. @@ -5379,7 +5404,7 @@ \item \tcode{n != numeric_limits::max()}\iref{numeric.limits} and -\tcode{n} characters have been extracted so far +\tcode{n} characters have been extracted so far; \item end-of-file occurs on the input sequence (in which case the function calls @@ -6156,12 +6181,12 @@ namespace std { template class basic_ostream::sentry { - bool ok_; // \expos + bool @\exposid{ok_}@; // \expos public: explicit sentry(basic_ostream& os); ~sentry(); - explicit operator bool() const { return ok_; } + explicit operator bool() const { return @\exposid{ok_}@; } sentry(const sentry&) = delete; sentry& operator=(const sentry&) = delete; @@ -6202,9 +6227,9 @@ \tcode{os.good()} is \tcode{true}, -\tcode{ok_ == true} +\tcode{\exposid{ok_} == true} otherwise, -\tcode{ok_ == false}. +\tcode{\exposid{ok_} == false}. During preparation, the constructor may call \tcode{setstate(failbit)} (which may throw @@ -6245,7 +6270,7 @@ \pnum \effects Returns -\tcode{ok_}. +\exposid{ok_}. \end{itemdescr} \rSec4[ostream.seeks]{Seek members} @@ -6341,7 +6366,7 @@ \tcode{*this}'s error state. If -\tcode{(exceptions()\&badbit) != 0} +\tcode{(exceptions() \& badbit) != 0} then the exception is rethrown. Whether or not an exception is thrown, the \tcode{sentry} @@ -6361,7 +6386,7 @@ If a formatted output function of a stream \tcode{os} determines padding, it does so as follows. Given a \tcode{charT} character sequence \tcode{seq} where -\tcode{charT} is the character type of the stream, if +\tcode{charT} is the character container type of the stream, if the length of \tcode{seq} is less than \tcode{os.width()}, then enough copies of \tcode{os.fill()} are added to this sequence as necessary to pad to a width of \tcode{os.width()} characters. If @@ -6413,9 +6438,8 @@ \tcode{const void*}, the formatting conversion occurs as if it performed the following code fragment: \begin{codeblock} -bool failed = use_facet< - num_put> - >(getloc()).put(*this, *this, fill(), val).failed(); +bool failed = use_facet>>( + getloc()).put(*this, *this, fill(), val).failed(); \end{codeblock} When \tcode{val} is of type @@ -6423,9 +6447,8 @@ the formatting conversion occurs as if it performed the following code fragment: \begin{codeblock} ios_base::fmtflags baseflags = ios_base::flags() & ios_base::basefield; -bool failed = use_facet< - num_put> - >(getloc()).put(*this, *this, fill(), +bool failed = use_facet>>( + getloc()).put(*this, *this, fill(), baseflags == ios_base::oct || baseflags == ios_base::hex ? static_cast(static_cast(val)) : static_cast(val)).failed(); @@ -6436,9 +6459,8 @@ the formatting conversion occurs as if it performed the following code fragment: \begin{codeblock} ios_base::fmtflags baseflags = ios_base::flags() & ios_base::basefield; -bool failed = use_facet< - num_put> - >(getloc()).put(*this, *this, fill(), +bool failed = use_facet>>( + getloc()).put(*this, *this, fill(), baseflags == ios_base::oct || baseflags == ios_base::hex ? static_cast(static_cast(val)) : static_cast(val)).failed(); @@ -6450,20 +6472,16 @@ \tcode{unsigned int} the formatting conversion occurs as if it performed the following code fragment: \begin{codeblock} -bool failed = use_facet< - num_put> - >(getloc()).put(*this, *this, fill(), - static_cast(val)).failed(); +bool failed = use_facet>>( + getloc()).put(*this, *this, fill(), static_cast(val)).failed(); \end{codeblock} When \tcode{val} is of type \tcode{float} the formatting conversion occurs as if it performed the following code fragment: \begin{codeblock} -bool failed = use_facet< - num_put> - >(getloc()).put(*this, *this, fill(), - static_cast(val)).failed(); +bool failed = use_facet>>( + getloc()).put(*this, *this, fill(), static_cast(val)).failed(); \end{codeblock} \pnum @@ -6520,20 +6538,16 @@ is less than or equal to that of \tcode{double}, the formatting conversion occurs as if it performed the following code fragment: \begin{codeblock} -bool failed = use_facet< - num_put> - >(getloc()).put(*this, *this, fill(), - static_cast(val)).failed(); +bool failed = use_facet>>( + getloc()).put(*this, *this, fill(), static_cast(val)).failed(); \end{codeblock} Otherwise, if the floating-point conversion rank of \tcode{\placeholder{extended-floating-point-type}} is less than or equal to that of \tcode{long double}, the formatting conversion occurs as if it performed the following code fragment: \begin{codeblock} -bool failed = use_facet< - num_put> - >(getloc()).put(*this, *this, fill(), - static_cast(val)).failed(); +bool failed = use_facet>>( + getloc()).put(*this, *this, fill(), static_cast(val)).failed(); \end{codeblock} Otherwise, an invocation of the operator function is conditionally supported with \impldef{\tcode{operator<<} for large extended floating-point types} @@ -6705,7 +6719,7 @@ of \tcode{out}. Constructs a character sequence \tcode{seq}. If \tcode{c} has type \tcode{char} -and the character type of the stream is not +and the character container type of the stream is not \tcode{char}, then \tcode{seq} consists of \tcode{out.widen(c)}; @@ -6789,11 +6803,11 @@ \effects If the ordinary literal encoding\iref{lex.charset} is UTF-8, equivalent to: \begin{codeblock} -vprint_unicode(os, fmt.@\exposid{str}@, make_format_args(std::forward(args)...)); +vprint_unicode(os, fmt.@\exposid{str}@, make_format_args(args...)); \end{codeblock} Otherwise, equivalent to: \begin{codeblock} -vprint_nonunicode(os, fmt.@\exposid{str}@, make_format_args(std::forward(args)...)); +vprint_nonunicode(os, fmt.@\exposid{str}@, make_format_args(args...)); \end{codeblock} \end{itemdescr} @@ -6808,7 +6822,21 @@ \effects Equivalent to: \begin{codeblock} -print(os, "{}\n", format(fmt, std::forward(args)...)); +print(os, "{}\n", format(os.getloc(), fmt, std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{println}% +\begin{itemdecl} +void println(ostream& os); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +print(os, "\n"); \end{codeblock} \end{itemdescr} @@ -6832,25 +6860,32 @@ without regard to the value of \tcode{os.exceptions()} and without turning on \tcode{ios_base::badbit} in the error state of \tcode{os}. \end{itemize} + +\par % This paragraph is part of the \effects clause. After constructing a \tcode{sentry} object, -the function initializes an automatic variable via +the function initializes a variable with automatic storage duration via \begin{codeblock} string out = vformat(os.getloc(), fmt, args); \end{codeblock} +\begin{itemize} +\item If the function is \tcode{vprint_unicode} and -\tcode{os} is a stream that refers to a terminal capable of displaying Unicode +\tcode{os} is a stream that refers to a terminal that +is capable of displaying Unicode only via a native Unicode API, which is determined in an implementation-defined manner, +flushes \tcode{os} and then writes \tcode{out} to the terminal using the native Unicode API; if \tcode{out} contains invalid code units, \indextext{undefined}% -the behavior is undefined and -implementations are encouraged to diagnose it. -If the native Unicode API is used, -the function flushes \tcode{os} before writing \tcode{out}. -Otherwise (if \tcode{os} is not such a stream or -the function is \tcode{vprint_nonunicode}), +the behavior is undefined. +Then establishes an observable checkpoint\iref{intro.abstract}. +\item +Otherwise inserts the character sequence \range{out.begin()}{out.end()} into \tcode{os}. +\end{itemize} + +\par % This paragraph is part of the \effects clause. If writing to the terminal or inserting into \tcode{os} fails, calls \tcode{os.setstate(ios_base::badbit)} (which may throw \tcode{ios_base::failure}). @@ -6988,7 +7023,7 @@ \tcode{*this}. \end{itemdescr} -\rSec3[ostream.manip]{Standard manipulators} +\rSec3[ostream.manip]{Standard \tcode{basic_ostream} manipulators} \pnum Each instantiation of any of the function templates @@ -7067,7 +7102,7 @@ To work around the issue that the \tcode{Allocator} template argument cannot be deduced, implementations can introduce an intermediate base class -to \tcode{basic_syncbuf} that manages its \tcode{emit_on_sync} flag. +to \tcode{basic_syncbuf} that manages its \exposid{emit-on-sync} flag. \end{note} \pnum @@ -7696,13 +7731,19 @@ \begin{itemdescr} \pnum \effects +Let \tcode{locksafe} be +\tcode{(enable_nonlocking_formatter_optimization> \&\& ...)}. If the ordinary literal encoding\iref{lex.charset} is UTF-8, equivalent to: \begin{codeblock} -vprint_unicode(stream, fmt.@\exposid{str}@, make_format_args(std::forward(args)...)); +locksafe + ? vprint_unicode(stream, fmt.str, make_format_args(args...)) + : vprint_unicode_buffered(stream, fmt.str, make_format_args(args...)); \end{codeblock} Otherwise, equivalent to: \begin{codeblock} -vprint_nonunicode(stream, fmt.@\exposid{str}@, make_format_args(std::forward(args)...)); +locksafe + ? vprint_nonunicode(stream, fmt.str, make_format_args(args...)) + : vprint_nonunicode_buffered(stream, fmt.str, make_format_args(args...)); \end{codeblock} \end{itemdescr} @@ -7721,6 +7762,20 @@ \end{codeblock} \end{itemdescr} +\indexlibraryglobal{println}% +\begin{itemdecl} +void println(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +println(stdout); +\end{codeblock} +\end{itemdescr} + \indexlibraryglobal{println}% \begin{itemdecl} template @@ -7732,7 +7787,21 @@ \effects Equivalent to: \begin{codeblock} -print(stream, "{}\n", format(fmt, std::forward(args)...)); +print(stream, runtime_format(string(fmt.get()) + '\n'), std::forward(args)...); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{println}% +\begin{itemdecl} +void println(FILE* stream); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +print(stream, "\n"); \end{codeblock} \end{itemdescr} @@ -7750,6 +7819,21 @@ \end{codeblock} \end{itemdescr} +\indexlibraryglobal{vprint_unicode_buffered}% +\begin{itemdecl} +void vprint_unicode_buffered(FILE* stream, string_view fmt, format_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +string out = vformat(fmt, args); +vprint_unicode(stream, "{}", make_format_args(out)); +\end{codeblock} +\end{itemdescr} + \indexlibraryglobal{vprint_unicode}% \begin{itemdecl} void vprint_unicode(FILE* stream, string_view fmt, format_args args); @@ -7762,28 +7846,32 @@ \pnum \effects -The function initializes an automatic variable via -\begin{codeblock} -string out = vformat(fmt, args); -\end{codeblock} -If \tcode{stream} refers to a terminal capable of displaying Unicode, +Locks \tcode{stream}. +Let \tcode{out} denote the character representation of +formatting arguments provided by \tcode{args} +formatted according to specifications given in \tcode{fmt}. +\begin{itemize} +\item +If \tcode{stream} refers to a terminal that +is capable of displaying Unicode only via a native Unicode API, +flushes \tcode{stream} and then writes \tcode{out} to the terminal using the native Unicode API; if \tcode{out} contains invalid code units, \indextext{undefined}% -the behavior is undefined and -implementations are encouraged to diagnose it. +the behavior is undefined. +Then establishes an observable checkpoint\iref{intro.abstract}. +\item Otherwise writes \tcode{out} to \tcode{stream} unchanged. -If the native Unicode API is used, -the function flushes \tcode{stream} before writing \tcode{out}. +\end{itemize} +Unconditionally unlocks \tcode{stream} on function exit. + +\xrefc{7.21.2}. + \begin{note} -On POSIX and Windows, \tcode{stream} referring to a terminal means that, -respectively, -\tcode{isatty(fileno(\linebreak{}stream))} and +On Windows the native Unicode API is \tcode{WriteConsoleW} and +\tcode{stream} referring to a terminal means that \tcode{GetConsoleMode(_get_osfhandle(_fileno(stream)), ...)} -return nonzero. -\end{note} -\begin{note} -On Windows, the native Unicode API is \tcode{WriteConsoleW}. +returns nonzero. \end{note} \pnum @@ -7814,6 +7902,21 @@ \end{codeblock} \end{itemdescr} +\indexlibraryglobal{vprint_nonunicode_buffered}% +\begin{itemdecl} +void vprint_nonunicode_buffered(FILE* stream, string_view fmt, format_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +string out = vformat(fmt, args); +vprint_nonunicode("{}", make_format_args(out)); +\end{codeblock} +\end{itemdescr} + \indexlibraryglobal{vprint_nonunicode}% \begin{itemdecl} void vprint_nonunicode(FILE* stream, string_view fmt, format_args args); @@ -7826,7 +7929,10 @@ \pnum \effects -Writes the result of \tcode{vformat(fmt, args)} to \tcode{stream}. +While holding the lock on \tcode{stream}, +writes the character representation of +formatting arguments provided by \tcode{args} +formatted according to specifications given in \tcode{fmt} to \tcode{stream}. \pnum \throws @@ -7858,6 +7964,7 @@ \indexlibraryglobal{basic_stringstream}% \begin{codeblock} namespace std { + // \ref{stringbuf}, class template \tcode{basic_stringbuf} template, class Allocator = allocator> class basic_stringbuf; @@ -7869,6 +7976,7 @@ using stringbuf = basic_stringbuf; using wstringbuf = basic_stringbuf; + // \ref{istringstream}, class template \tcode{basic_istringstream} template, class Allocator = allocator> class basic_istringstream; @@ -7880,6 +7988,7 @@ using istringstream = basic_istringstream; using wistringstream = basic_istringstream; + // \ref{ostringstream}, class template \tcode{basic_ostringstream} template, class Allocator = allocator> class basic_ostringstream; @@ -7891,6 +8000,7 @@ using ostringstream = basic_ostringstream; using wostringstream = basic_ostringstream; + // \ref{stringstream}, class template \tcode{basic_stringstream} template, class Allocator = allocator> class basic_stringstream; @@ -7993,15 +8103,15 @@ pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which - = ios_base::in | ios_base::out) override; + = ios_base::in | ios_base::out) override; pos_type seekpos(pos_type sp, ios_base::openmode which - = ios_base::in | ios_base::out) override; + = ios_base::in | ios_base::out) override; private: - ios_base::openmode mode; // \expos - basic_string buf; // \expos - void init_buf_ptrs(); // \expos + ios_base::openmode @\exposid{mode}@; // \expos + basic_string @\exposid{buf}@; // \expos + void @\exposid{init-buf-ptrs}@(); // \expos }; } \end{codeblock} @@ -8022,17 +8132,17 @@ the maintained data and internal pointer initialization is presented here as: \begin{itemize} \item - \tcode{ios_base::openmode mode}, has + \tcode{ios_base::openmode \exposid{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} + \tcode{basic_string \exposid{buf}} contains the underlying character sequence. \item - \tcode{init_buf_ptrs()} sets the base class' + \tcode{\exposid{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. + after initializing, moving from, or assigning to \exposid{buf} accordingly. \end{itemize} \rSec3[stringbuf.cons]{Constructors} @@ -8047,7 +8157,7 @@ \effects Initializes the base class with \tcode{basic_streambuf()}\iref{streambuf.cons}, and -\tcode{mode} +\exposid{mode} with \tcode{which}. It is \impldef{whether sequence pointers are initialized to null pointers} @@ -8073,14 +8183,14 @@ \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()}. +\exposid{mode} with \tcode{which}, and +\exposid{buf} with \tcode{s}, +then calls \tcode{\exposid{init-buf-ptrs}()}. \end{itemdescr} \indexlibraryctor{basic_stringbuf}% \begin{itemdecl} -basic_stringbuf(ios_base::openmode which, const Allocator &a); +basic_stringbuf(ios_base::openmode which, const Allocator& a); \end{itemdecl} \begin{itemdescr} @@ -8088,9 +8198,9 @@ \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()}. +\exposid{mode} with \tcode{which}, and +\exposid{buf} with \tcode{a}, +then calls \tcode{\exposid{init-buf-ptrs}()}. \pnum \ensures @@ -8108,9 +8218,9 @@ \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()}. +\exposid{mode} with \tcode{which}, and +\exposid{buf} with \tcode{std::move(s)}, +then calls \tcode{\exposid{init-buf-ptrs}()}. \end{itemdescr} \indexlibraryctor{basic_stringbuf}% @@ -8118,16 +8228,16 @@ template basic_stringbuf( const basic_string& s, - ios_base::openmode which, const Allocator &a); + 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()}. +\exposid{mode} with \tcode{which}, and +\exposid{buf} with \tcode{\{s,a\}}, +then calls \tcode{\exposid{init-buf-ptrs}()}. \end{itemdescr} \indexlibraryctor{basic_stringbuf}% @@ -8146,9 +8256,9 @@ \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()}. +\exposid{mode} with \tcode{which}, and +\exposid{buf} with \tcode{s}, +then calls \tcode{\exposid{init-buf-ptrs}()}. \end{itemdescr} \indexlibraryctor{basic_stringbuf}% @@ -8177,9 +8287,9 @@ Creates a variable \tcode{sv} as if by \tcode{basic_string_view sv = t}, then value-initializes the base class, -initializes \tcode{mode} with \tcode{which}, and -direct-non-list-initializes \tcode{buf} with \tcode{sv, a}, -then calls \tcode{init_buf_ptrs()}. +initializes \exposid{mode} with \tcode{which}, and +direct-non-list-initializes \exposid{buf} with \tcode{sv, a}, +then calls \tcode{\exposid{init-buf-ptrs}()}. \end{itemdescr} \indexlibraryctor{basic_stringbuf}% @@ -8192,10 +8302,10 @@ \pnum \effects Copy constructs the base class from \tcode{rhs} and -initializes \tcode{mode} with \tcode{rhs.mode}. +initializes \exposid{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 +In the second form \exposid{buf} is initialized from \tcode{\{std::move(rhs).str(), a\}}. It is \impldef{whether sequence pointers are copied by \tcode{basic_stringbuf} move @@ -8300,39 +8410,39 @@ (except for those characters re-initialized by the new \tcode{basic_string}). \begin{itemdecl} -void init_buf_ptrs(); // \expos +void @\exposid{init-buf-ptrs}@(); // \expos \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes the input and output sequences from \tcode{buf} -according to \tcode{mode}. +Initializes the input and output sequences from \exposid{buf} +according to \exposid{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}; +\item If \tcode{ios_base::out} is set in \exposid{mode}, + \tcode{pbase()} points to \tcode{\exposid{buf}.front()} and + \tcode{epptr() >= pbase() + \exposid{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 in addition, if \tcode{ios_base::ate} is set in \exposid{mode}, + \tcode{pptr() == pbase() + \exposid{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())} +\item If \tcode{ios_base::in} is set in \exposid{mode}, + \tcode{eback()} points to \tcode{\exposid{buf}.front()}, and + \tcode{(gptr() == eback() \&\& egptr() == eback() + \exposid{buf}.size())} is \tcode{true}. \end{itemize} \pnum \begin{note} For efficiency reasons, -stream buffer operations can violate invariants of \tcode{buf} +stream buffer operations can violate invariants of \exposid{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()}}. +\range{\tcode{\exposid{buf}.data() + \exposid{buf}.size()}}{\tcode{\exposid{buf}.data() + \exposid{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} @@ -8346,7 +8456,7 @@ \begin{itemdescr} \pnum \returns -\tcode{buf.get_allocator()}. +\tcode{\exposid{buf}.get_allocator()}. \end{itemdescr} \indexlibrarymember{str}{basic_stringbuf}% @@ -8393,7 +8503,7 @@ 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()} +are initialized as if by calling \tcode{\exposid{init-buf-ptrs}()} with an empty \tcode{buf}. \pnum @@ -8419,10 +8529,10 @@ 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 If \tcode{ios_base::out} is set in \exposid{mode}, + then \tcode{sv(pbase(), high_mark - pbase())} is returned. +\item Otherwise, if \tcode{ios_base::in} is set in \exposid{mode}, + then \tcode{sv(eback(), egptr() - eback())} is returned. \item Otherwise, \tcode{sv()} is returned. \end{itemize} @@ -8444,8 +8554,8 @@ \effects Equivalent to: \begin{codeblock} -buf = s; -init_buf_ptrs(); +@\exposid{buf}@ = s; +@\exposid{init-buf-ptrs}@(); \end{codeblock} \end{itemdescr} @@ -8464,8 +8574,8 @@ \effects Equivalent to: \begin{codeblock} -buf = s; -init_buf_ptrs(); +@\exposid{buf}@ = s; +@\exposid{init-buf-ptrs}@(); \end{codeblock} \end{itemdescr} @@ -8479,8 +8589,8 @@ \effects Equivalent to: \begin{codeblock} -buf = std::move(s); -init_buf_ptrs(); +@\exposid{buf}@ = std::move(s); +@\exposid{init-buf-ptrs}@(); \end{codeblock} \end{itemdescr} @@ -8501,8 +8611,8 @@ Equivalent to: \begin{codeblock} basic_string_view sv = t; -buf = sv; -init_buf_ptrs(); +@\exposid{buf}@ = sv; +@\exposid{init-buf-ptrs}@(); \end{codeblock} \end{itemdescr} @@ -8561,7 +8671,7 @@ \tcode{false} and if the input sequence has a putback position available, and -if \tcode{mode} +if \exposid{mode} \tcode{\&} \tcode{ios_base::out} is nonzero, @@ -8647,14 +8757,14 @@ \pnum The function can make a write position available only if -\tcode{ios_base::out} is set in \tcode{mode}. +\tcode{ios_base::out} is set in \exposid{mode}. To make a write position available, the function reallocates (or initially allocates) an array object with a sufficient number of elements to hold the current array object (if any), plus at least one additional write position. -If \tcode{ios_base::in} is set in \tcode{mode}, +If \tcode{ios_base::in} is set in \exposid{mode}, the function alters the read end pointer \tcode{egptr()} to point just past the new write position. @@ -8842,7 +8952,7 @@ void str(const T& t); private: - basic_stringbuf sb; // \expos + basic_stringbuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -8858,7 +8968,7 @@ For the sake of exposition, the maintained data is presented here as: \begin{itemize} \item -\tcode{sb}, the \tcode{stringbuf} object. +\exposid{sb}, the \tcode{stringbuf} object. \end{itemize} \rSec3[istringstream.cons]{Constructors} @@ -8872,8 +8982,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream} +and \exposid{sb} with \tcode{basic_stringbuf(which | ios_base::in)}\iref{stringbuf.cons}. \end{itemdescr} @@ -8888,8 +8998,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream} +and \exposid{sb} with \tcode{basic_stringbuf(s, which | ios_base::in)}\linebreak\iref{stringbuf.cons}. % avoid Overfull \end{itemdescr} @@ -8902,8 +9012,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream} +and \exposid{sb} with \tcode{basic_stringbuf(which | ios_base::in, a)}\iref{stringbuf.cons}. \end{itemdescr} @@ -8918,8 +9028,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream} +and \exposid{sb} with \tcode{basic_stringbuf(std::move(s), which | ios_base::\brk{}in)}\iref{stringbuf.cons}. \end{itemdescr} @@ -8935,8 +9045,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream} +and \exposid{sb} with \tcode{basic_stringbuf(s, which | ios_base::in, a)}\linebreak\iref{stringbuf.cons}. % avoid Overfull \end{itemdescr} @@ -8956,8 +9066,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream} +and \exposid{sb} with \tcode{basic_stringbuf(s, which | ios_base::in)}\iref{stringbuf.cons}. \end{itemdescr} @@ -8984,8 +9094,8 @@ \pnum \effects -Initializes the base class with \tcode{addressof(sb)}, and -direct-non-list-initializes \tcode{sb} with \tcode{t, which | ios_base::in, a}. +Initializes the base class with \tcode{addressof(\exposid{sb})}, and +direct-non-list-initializes \exposid{sb} with \tcode{t, which | ios_base::in, a}. \end{itemdescr} \indexlibraryctor{basic_istringstream}% @@ -8999,7 +9109,7 @@ Move constructs from the rvalue \tcode{rhs}. This is accomplished by move constructing the base class, and the contained \tcode{basic_stringbuf}. -Then calls \tcode{basic_istream::set_rdbuf(addressof(sb))} +Then calls \tcode{basic_istream::set_rdbuf(addressof(\exposid{sb}))} to install the contained \tcode{basic_stringbuf}. \end{itemdescr} @@ -9016,7 +9126,7 @@ Equivalent to: \begin{codeblock} basic_istream::swap(rhs); -sb.swap(rhs.sb); +@\exposid{sb}@.swap(rhs.@\exposid{sb}@); \end{codeblock} \end{itemdescr} @@ -9044,7 +9154,7 @@ \begin{itemdescr} \pnum \returns -\tcode{const_cast*>(addressof(sb))}. +\tcode{const_cast*>(addressof(\exposid{sb}))}. \end{itemdescr} \indexlibrarymember{str}{basic_istringstream}% @@ -9215,7 +9325,7 @@ void str(const T& t); private: - basic_stringbuf sb; // \expos + basic_stringbuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -9231,7 +9341,7 @@ For the sake of exposition, the maintained data is presented here as: \begin{itemize} \item -\tcode{sb}, the \tcode{stringbuf} object. +\exposid{sb}, the \tcode{stringbuf} object. \end{itemize} \rSec3[ostringstream.cons]{Constructors} @@ -9245,8 +9355,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream} +and \exposid{sb} with \tcode{basic_stringbuf(which | ios_base::out)}\iref{stringbuf.cons}. \end{itemdescr} @@ -9261,8 +9371,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream} +and \exposid{sb} with \tcode{basic_stringbuf(s, which | ios_base::out)}\linebreak\iref{stringbuf.cons}. % avoid Overfull \end{itemdescr} @@ -9275,8 +9385,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream} +and \exposid{sb} with \tcode{basic_stringbuf(which | ios_base::out, a)}\linebreak\iref{stringbuf.cons}. % avoid Overfull \end{itemdescr} @@ -9291,8 +9401,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream} +and \exposid{sb} with \tcode{basic_stringbuf(std::move(s), which | ios_base::\brk{}out)}\iref{stringbuf.cons}. \end{itemdescr} @@ -9308,8 +9418,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream} +and \exposid{sb} with \tcode{basic_stringbuf(s, which | ios_base::out, a)}\linebreak\iref{stringbuf.cons}. % avoid Overfull \end{itemdescr} @@ -9329,8 +9439,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream} +and \exposid{sb} with \tcode{basic_stringbuf(s, which | ios_base::out)}\linebreak\iref{stringbuf.cons}. % avoid Overfull \end{itemdescr} @@ -9357,8 +9467,8 @@ \pnum \effects -Initializes the base class with \tcode{addressof(sb)}, and -direct-non-list-initializes \tcode{sb} with \tcode{t, which | ios_base::out, a}. +Initializes the base class with \tcode{addressof(\exposid{sb})}, and +direct-non-list-initializes \exposid{sb} with \tcode{t, which | ios_base::out, a}. \end{itemdescr} \indexlibraryctor{basic_ostringstream}% @@ -9372,7 +9482,7 @@ Move constructs from the rvalue \tcode{rhs}. This is accomplished by move constructing the base class, and the contained \tcode{basic_stringbuf}. -Then calls \tcode{basic_ostream::set_rdbuf(addressof(sb))} +Then calls \tcode{basic_ostream::set_rdbuf(addressof(\exposid{sb}))} to install the contained \tcode{basic_stringbuf}. \end{itemdescr} @@ -9389,7 +9499,7 @@ Equivalent to: \begin{codeblock} basic_ostream::swap(rhs); -sb.swap(rhs.sb); +@\exposid{sb}@.swap(rhs.@\exposid{sb}@); \end{codeblock} \end{itemdescr} @@ -9416,7 +9526,7 @@ \begin{itemdescr} \pnum \returns -\tcode{const_cast*>(addressof(sb))}. +\tcode{const_cast*>(addressof(\exposid{sb}))}. \end{itemdescr} \indexlibrarymember{str}{basic_ostringstream}% @@ -9588,7 +9698,7 @@ void str(const T& t); private: - basic_stringbuf sb; // \expos + basic_stringbuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -9605,7 +9715,7 @@ For the sake of exposition, the maintained data is presented here as \begin{itemize} \item -\tcode{sb}, the \tcode{stringbuf} object. +\exposid{sb}, the \tcode{stringbuf} object. \end{itemize} \rSec3[stringstream.cons]{Constructors} @@ -9619,9 +9729,9 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} and -\tcode{sb} +\exposid{sb} with \tcode{basic_string\-buf(which)}. \end{itemdescr} @@ -9637,9 +9747,9 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} and -\tcode{sb} +\exposid{sb} with \tcode{basic_string\-buf(s, which)}. \end{itemdescr} @@ -9653,8 +9763,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} -and \tcode{sb} with +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} +and \exposid{sb} with \tcode{basic_stringbuf(which, a)}\iref{stringbuf.cons}. \end{itemdescr} @@ -9669,8 +9779,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} -and \tcode{sb} with +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} +and \exposid{sb} with \tcode{basic_stringbuf(std::move(s), which)}\iref{stringbuf.cons}. \end{itemdescr} @@ -9686,8 +9796,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} -and \tcode{sb} with +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} +and \exposid{sb} with \tcode{basic_stringbuf(s, which, a)}\iref{stringbuf.cons}. \end{itemdescr} @@ -9707,8 +9817,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} -and \tcode{sb} with +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} +and \exposid{sb} with \tcode{basic_stringbuf(s, which)}\iref{stringbuf.cons}. \end{itemdescr} @@ -9735,8 +9845,8 @@ \pnum \effects -Initializes the base class with \tcode{addressof(sb)}, and -direct-non-list-initializes \tcode{sb} with \tcode{t, which, a}. +Initializes the base class with \tcode{addressof(\exposid{sb})}, and +direct-non-list-initializes \exposid{sb} with \tcode{t, which, a}. \end{itemdescr} \indexlibraryctor{basic_stringstream}% @@ -9750,7 +9860,7 @@ Move constructs from the rvalue \tcode{rhs}. This is accomplished by move constructing the base class, and the contained \tcode{basic_stringbuf}. -Then calls \tcode{basic_istream::set_rdbuf(addressof(sb))} +Then calls \tcode{basic_istream::set_rdbuf(addressof(\exposid{sb}))} to install the contained \tcode{basic_stringbuf}. \end{itemdescr} @@ -9767,7 +9877,7 @@ Equivalent to: \begin{codeblock} basic_iostream::swap(rhs); -sb.swap(rhs.sb); +@\exposid{sb}@.swap(rhs.@\exposid{sb}@); \end{codeblock} \end{itemdescr} @@ -9794,7 +9904,7 @@ \begin{itemdescr} \pnum \returns -\tcode{const_cast*>(addressof(sb))}. +\tcode{const_cast*>(addressof(\exposid{sb}))}. \end{itemdescr} \indexlibrarymember{str}{basic_stringstream}% @@ -9904,7 +10014,7 @@ \begin{note} A user of these classes is responsible for ensuring that the character sequence represented by the given \tcode{span} -outlives the use of the sequence by objects of the classes in subclause \ref{span.streams}. +outlives the use of the sequence by objects of the classes in \ref{span.streams}. Using multiple \tcode{basic_spanbuf} objects referring to overlapping underlying sequences from different threads, where at least one \tcode{basic_spanbuf} object is used @@ -9924,6 +10034,7 @@ \indexlibraryglobal{wspanstream}% \begin{codeblock} namespace std { + // \ref{spanbuf}, class template \tcode{basic_spanbuf} template> class basic_spanbuf; @@ -9933,6 +10044,7 @@ using spanbuf = basic_spanbuf; using wspanbuf = basic_spanbuf; + // \ref{ispanstream}, class template \tcode{basic_ispanstream} template> class basic_ispanstream; @@ -9942,6 +10054,7 @@ using ispanstream = basic_ispanstream; using wispanstream = basic_ispanstream; + // \ref{ospanstream}, class template \tcode{basic_ospanstream} template> class basic_ospanstream; @@ -9951,6 +10064,7 @@ using ospanstream = basic_ospanstream; using wospanstream = basic_ospanstream; + // \ref{spanstream}, class template \tcode{basic_spanstream} template> class basic_spanstream; @@ -10008,7 +10122,7 @@ private: ios_base::openmode @\exposid{mode}@; // \expos std::span @\exposid{buf}@; // \expos -}; + }; } \end{codeblock} @@ -10239,7 +10353,7 @@ if \tcode{ios_base::out} is set in \exposid{mode} and \tcode{ios_base::in} is not set in \exposid{mode}, \item -\tcode{buf.size()} otherwise. +\tcode{\exposid{buf}.size()} otherwise. \end{itemize} \end{itemize} @@ -10327,7 +10441,7 @@ template void span(ROS&& s) noexcept; private: - basic_spanbuf sb; // \expos + basic_spanbuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -10350,8 +10464,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))} +and \exposid{sb} with \tcode{basic_spanbuf(s, which | ios_base::in)}\iref{spanbuf.cons}. \end{itemdescr} @@ -10364,9 +10478,9 @@ \pnum \effects Initializes the base class with \tcode{std::move(rhs)} -and \tcode{sb} with \tcode{std::move(rhs.sb)}. -Next, \tcode{basic_istream::set_rdbuf(addressof(sb))} is called -to install the contained \tcode{basic_spanbuf}. +and \exposid{sb} with \tcode{std::move(rhs.\exposid{sb})}. +Next, \tcode{basic_istream::set_rdbuf(addressof(\exposid{sb}))} is called +to install the contained \tcode{ba\-sic_\-span\-buf}. \end{itemdescr} \indexlibraryctor{basic_ispanstream}% @@ -10403,7 +10517,7 @@ Equivalent to: \begin{codeblock} basic_istream::swap(rhs); -sb.swap(rhs.sb); +@\exposid{sb}@.swap(rhs.@\exposid{sb}@); \end{codeblock} \end{itemdescr} @@ -10431,7 +10545,7 @@ \effects Equivalent to: \begin{codeblock} -return const_cast*>(addressof(sb)); +return const_cast*>(addressof(@\exposid{sb}@)); \end{codeblock} \end{itemdescr} @@ -10513,7 +10627,7 @@ void span(std::span s) noexcept; private: - basic_spanbuf sb; // \expos + basic_spanbuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -10530,8 +10644,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))} +and \exposid{sb} with \tcode{basic_spanbuf(s, which | ios_base::out)}\iref{spanbuf.cons}. \end{itemdescr} @@ -10544,9 +10658,9 @@ \pnum \effects Initializes the base class with \tcode{std::move(rhs)} -and \tcode{sb} with \tcode{std::move(rhs.sb)}. -Next, \tcode{basic_ostream::set_rdbuf(addressof(sb))} -is called to install the contained \tcode{basic_spanbuf}. +and \exposid{sb} with \tcode{std::move(rhs.\exposid{sb})}. +Next, \tcode{basic_ostream::set_rdbuf(addressof(\exposid{sb}))} +is called to install the contained \tcode{ba\-sic_\-span\-buf}. \end{itemdescr} \rSec3[ospanstream.swap]{Swap} @@ -10562,7 +10676,7 @@ Equivalent to: \begin{codeblock} basic_ostream::swap(rhs); -sb.swap(rhs.sb); +@\exposid{sb}@.swap(rhs.@\exposid{sb}@); \end{codeblock} \end{itemdescr} @@ -10590,7 +10704,7 @@ \effects Equivalent to: \begin{codeblock} -return const_cast*>(addressof(sb)); +return const_cast*>(addressof(@\exposid{sb}@)); \end{codeblock} \end{itemdescr} @@ -10652,7 +10766,7 @@ void span(std::span s) noexcept; private: - basic_spanbuf sb; // \expos + basic_spanbuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -10669,8 +10783,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))} -and \tcode{sb} with +\tcode{basic_iostream(addressof(\exposid{sb}))} +and \exposid{sb} with \tcode{basic_spanbuf(s, which)}\iref{spanbuf.cons}. \end{itemdescr} @@ -10683,8 +10797,8 @@ \pnum \effects Initializes the base class with \tcode{std::move(rhs)} -and \tcode{sb} with \tcode{std::move(rhs.sb)}. -Next, \tcode{basic_iostream::set_rdbuf(addressof(sb))} +and \exposid{sb} with \tcode{std::move(rhs.\exposid{sb})}. +Next, \tcode{basic_iostream::set_rdbuf(addressof(\exposid{sb}))} is called to install the contained \tcode{basic_spanbuf}. \end{itemdescr} @@ -10701,7 +10815,7 @@ Equivalent to: \begin{codeblock} basic_iostream::swap(rhs); -sb.swap(rhs.sb); +@\exposid{sb}@.swap(rhs.@\exposid{sb}@); \end{codeblock} \end{itemdescr} @@ -10729,7 +10843,7 @@ \effects Equivalent to: \begin{codeblock} -return const_cast*>(addressof(sb)); +return const_cast*>(addressof(@\exposid{sb}@)); \end{codeblock} \end{itemdescr} @@ -10778,6 +10892,7 @@ \indexlibraryglobal{basic_fstream}% \begin{codeblock} namespace std { + // \ref{filebuf}, class template \tcode{basic_filebuf} template> class basic_filebuf; @@ -10787,6 +10902,7 @@ using filebuf = basic_filebuf; using wfilebuf = basic_filebuf; + // \ref{ifstream}, class template \tcode{basic_ifstream} template> class basic_ifstream; @@ -10796,6 +10912,7 @@ using ifstream = basic_ifstream; using wifstream = basic_ifstream; + // \ref{ofstream}, class template \tcode{basic_ofstream} template> class basic_ofstream; @@ -10805,6 +10922,7 @@ using ofstream = basic_ofstream; using wofstream = basic_ofstream; + // \ref{fstream}, class template \tcode{basic_fstream} template> class basic_fstream; @@ -11116,7 +11234,7 @@ \begin{itemdescr} \pnum \expects -\tcode{s} points to a NTCTS\iref{defns.ntcts}. +\tcode{s} points to an NTCTS\iref{defns.ntcts}. \pnum \effects @@ -11461,6 +11579,7 @@ At this point if \tcode{b != p} and \tcode{b == end} (\tcode{xbuf} isn't large enough) then increase \tcode{XSIZE} and repeat from the beginning. \end{itemize} +Then establishes an observable checkpoint\iref{intro.abstract}. \pnum \returns @@ -11704,7 +11823,7 @@ void close(); private: - basic_filebuf sb; // \expos + basic_filebuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -11720,7 +11839,7 @@ For the sake of exposition, the maintained data is presented here as: \begin{itemize} \item -\tcode{sb}, the \tcode{filebuf} object. +\exposid{sb}, the \tcode{filebuf} object. \end{itemize} \rSec3[ifstream.cons]{Constructors} @@ -11734,8 +11853,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream.cons} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream.cons} +and \exposid{sb} with \tcode{basic_filebuf()}\iref{filebuf.cons}. \end{itemdescr} @@ -11751,8 +11870,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_istream(addressof(sb))}\iref{istream.cons} -and \tcode{sb} with +\tcode{basic_istream(addressof(\exposid{sb}))}\iref{istream.cons} +and \exposid{sb} with \tcode{basic_filebuf()}\iref{filebuf.cons}, then calls \tcode{rdbuf()->open(s, mode | ios_base::in)}. @@ -11797,7 +11916,7 @@ \pnum \effects Move constructs the base class, and the contained \tcode{basic_filebuf}. -Then calls \tcode{basic_istream::set_rdbuf(\brk{}addressof(sb))} +Then calls \tcode{basic_istream::set_rdbuf(\brk{}addressof(\exposid{sb}))} to install the contained \tcode{basic_filebuf}. \end{itemdescr} @@ -11814,7 +11933,7 @@ Exchanges the state of \tcode{*this} and \tcode{rhs} by calling \tcode{basic_istream::swap(rhs)} and -\tcode{sb.swap(rhs.sb)}. +\tcode{\exposid{sb}.swap(rhs.\exposid{sb})}. \end{itemdescr} \indexlibrarymember{swap}{basic_ifstream}% @@ -11839,7 +11958,7 @@ \begin{itemdescr} \pnum \returns -\tcode{const_cast*>(addressof(sb))}. +\tcode{const_cast*>(addressof(\exposid{sb}))}. \end{itemdescr} \indexlibrarymember{native_handle}{basic_ifstream}% @@ -11963,7 +12082,7 @@ void close(); private: - basic_filebuf sb; // \expos + basic_filebuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -11979,7 +12098,7 @@ For the sake of exposition, the maintained data is presented here as: \begin{itemize} \item -\tcode{sb}, the \tcode{filebuf} object. +\exposid{sb}, the \tcode{filebuf} object. \end{itemize} \rSec3[ofstream.cons]{Constructors} @@ -11993,8 +12112,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream.cons} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream.cons} +and \exposid{sb} with \tcode{basic_filebuf()}\iref{filebuf.cons}. \end{itemdescr} @@ -12010,8 +12129,8 @@ \pnum \effects Initializes the base class with -\tcode{basic_ostream(addressof(sb))}\iref{ostream.cons} -and \tcode{sb} with +\tcode{basic_ostream(addressof(\exposid{sb}))}\iref{ostream.cons} +and \exposid{sb} with \tcode{basic_filebuf()}\iref{filebuf.cons}, then calls \tcode{rdbuf()->open(s, mode | ios_base::out)}. @@ -12056,7 +12175,7 @@ \pnum \effects Move constructs the base class, and the contained \tcode{basic_filebuf}. -Then calls \tcode{basic_ostream::set_rdbuf(\brk{}addressof(sb))} +Then calls \tcode{basic_ostream::set_rdbuf(\brk{}addressof(\exposid{sb}))} to install the contained \tcode{basic_filebuf}. \end{itemdescr} @@ -12073,7 +12192,7 @@ Exchanges the state of \tcode{*this} and \tcode{rhs} by calling \tcode{basic_ostream::swap(rhs)} and -\tcode{sb.swap(rhs.sb)}. +\tcode{\exposid{sb}.swap(rhs.\exposid{sb})}. \end{itemdescr} \indexlibrarymember{swap}{basic_ofstream}% @@ -12098,7 +12217,7 @@ \begin{itemdescr} \pnum \returns -\tcode{const_cast*>(addressof(sb))}. +\tcode{const_cast*>(addressof(\exposid{sb}))}. \end{itemdescr} \indexlibrarymember{native_handle}{basic_ofstream}% @@ -12195,7 +12314,7 @@ ios_base::openmode mode = ios_base::in | ios_base::out); explicit basic_fstream( const filesystem::path::value_type* s, - ios_base::openmode mode = ios_base::in|ios_base::out); // wide systems only; see \ref{fstream.syn} + ios_base::openmode mode = ios_base::in | ios_base::out); // wide systems only; see \ref{fstream.syn} explicit basic_fstream( const string& s, ios_base::openmode mode = ios_base::in | ios_base::out); @@ -12220,7 +12339,7 @@ ios_base::openmode mode = ios_base::in | ios_base::out); void open( const filesystem::path::value_type* s, - ios_base::openmode mode = ios_base::in|ios_base::out); // wide systems only; see \ref{fstream.syn} + ios_base::openmode mode = ios_base::in | ios_base::out); // wide systems only; see \ref{fstream.syn} void open( const string& s, ios_base::openmode mode = ios_base::in | ios_base::out); @@ -12230,7 +12349,7 @@ void close(); private: - basic_filebuf sb; // \expos + basic_filebuf @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -12246,7 +12365,7 @@ For the sake of exposition, the maintained data is presented here as: \begin{itemize} \item -\tcode{sb}, the \tcode{basic_filebuf} object. +\exposid{sb}, the \tcode{basic_filebuf} object. \end{itemize} \rSec3[fstream.cons]{Constructors} @@ -12260,9 +12379,9 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} and -\tcode{sb} with \tcode{basic_filebuf()}. +\exposid{sb} with \tcode{basic_filebuf()}. \end{itemdescr} \indexlibraryctor{basic_fstream}% @@ -12279,9 +12398,9 @@ \pnum \effects Initializes the base class with -\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +\tcode{basic_iostream(addressof(\exposid{sb}))}\iref{iostream.cons} and -\tcode{sb} with \tcode{basic_filebuf()}. +\exposid{sb} with \tcode{basic_filebuf()}. Then calls \tcode{rdbuf()->open(s, mode)}. If that function returns a null pointer, calls @@ -12326,7 +12445,7 @@ \pnum \effects Move constructs the base class, and the contained \tcode{basic_filebuf}. -Then calls \tcode{basic_istream::set_rdbuf(\brk{}addressof(sb))} +Then calls \tcode{basic_istream::set_rdbuf(\brk{}addressof(\exposid{sb}))} to install the contained \tcode{basic_filebuf}. \end{itemdescr} @@ -12343,7 +12462,7 @@ Exchanges the state of \tcode{*this} and \tcode{rhs} by calling \tcode{basic_iostream::swap(rhs)} and -\tcode{sb.swap(rhs.sb)}. +\tcode{\exposid{sb}.swap(rhs.\exposid{sb})}. \end{itemdescr} \indexlibrarymember{swap}{basic_fstream}% @@ -12369,7 +12488,7 @@ \begin{itemdescr} \pnum \returns -\tcode{const_cast*>(addressof(sb))}. +\tcode{const_cast*>(addressof(\exposid{sb}))}. \end{itemdescr} \indexlibrarymember{native_handle}{basic_fstream}% @@ -12463,6 +12582,7 @@ #include // see \ref{ostream.syn} namespace std { + // \ref{syncstream.syncbuf}, class template \tcode{basic_syncbuf} template, class Allocator = allocator> class basic_syncbuf; @@ -12474,6 +12594,7 @@ using syncbuf = basic_syncbuf; using wsyncbuf = basic_syncbuf; + // \ref{syncstream.osyncstream}, class template \tcode{basic_osyncstream} template, class Allocator = allocator> class basic_osyncstream; @@ -12529,8 +12650,8 @@ int sync() override; private: - streambuf_type* wrapped; // \expos - bool emit_on_sync{}; // \expos + streambuf_type* @\exposid{wrapped}@; // \expos + bool @\exposid{emit-on-sync}@{}; // \expos }; } \end{codeblock} @@ -12540,7 +12661,7 @@ written to it, known as the associated output, into internal buffers allocated using the object's allocator. The associated output is transferred to the -wrapped stream buffer object \tcode{*wrapped} +wrapped stream buffer object \tcode{*\exposid{wrapped}} when \tcode{emit()} is called or when the \tcode{basic_syncbuf} object is destroyed. Such transfers are atomic with respect to transfers @@ -12557,7 +12678,7 @@ \begin{itemdescr} \pnum \effects -Sets \tcode{wrapped} to \tcode{obuf}. +Sets \exposid{wrapped} to \tcode{obuf}. \pnum \ensures @@ -12691,10 +12812,10 @@ \pnum \effects Atomically transfers the associated output of \tcode{*this} -to the stream buffer \tcode{*wrapped}, +to the stream buffer \tcode{*\exposid{wrapped}}, so that it appears in the output stream as a contiguous sequence of characters. -\tcode{wrapped->pubsync()} is called +\tcode{\exposid{wrapped}->pubsync()} is called if and only if a call was made to \tcode{sync()} since the most recent call to \tcode{emit()}, if any. @@ -12717,15 +12838,15 @@ \tcode{true} if all of the following conditions hold; otherwise \tcode{false}: \begin{itemize} -\item \tcode{wrapped == nullptr} is \tcode{false}. +\item \tcode{\exposid{wrapped} == nullptr} is \tcode{false}. \item All of the characters in the associated output were successfully transferred. -\item The call to \tcode{wrapped->pubsync()} (if any) succeeded. +\item The call to \tcode{\exposid{wrapped}->pubsync()} (if any) succeeded. \end{itemize} \pnum \remarks -May call member functions of \tcode{wrapped} -while holding a lock uniquely associated with \tcode{wrapped}. +May call member functions of \exposid{wrapped} +while holding a lock uniquely associated with \exposid{wrapped}. \end{itemdescr} \indexlibrarymember{get_wrapped}{basic_syncbuf}% @@ -12736,7 +12857,7 @@ \begin{itemdescr} \pnum \returns -\tcode{wrapped}. +\exposid{wrapped}. \end{itemdescr} \indexlibrarymember{get_allocator}{basic_syncbuf}% @@ -12758,7 +12879,7 @@ \begin{itemdescr} \pnum \effects -\tcode{emit_on_sync = b}. +\tcode{\exposid{emit-on-sync} = b}. \end{itemdescr} \rSec3[syncstream.syncbuf.virtuals]{Overridden virtual functions} @@ -12772,9 +12893,9 @@ \pnum \effects Records that the wrapped stream buffer is to be flushed. -Then, if \tcode{emit_on_sync} is \tcode{true}, calls \tcode{emit()}. +Then, if \exposid{emit-on-sync} is \tcode{true}, calls \tcode{emit()}. \begin{note} -If \tcode{emit_on_sync} is \tcode{false}, +If \exposid{emit-on-sync} is \tcode{false}, the actual flush is delayed until a call to \tcode{emit()}. \end{note} @@ -12836,10 +12957,10 @@ // \ref{syncstream.osyncstream.members}, member functions void emit(); streambuf_type* get_wrapped() const noexcept; - syncbuf_type* rdbuf() const noexcept { return const_cast(addressof(sb)); } + syncbuf_type* rdbuf() const noexcept { return const_cast(addressof(@\exposid{sb}@)); } private: - syncbuf_type sb; // \expos + syncbuf_type @\exposid{sb}@; // \expos }; } \end{codeblock} @@ -12881,8 +13002,8 @@ \begin{itemdescr} \pnum \effects -Initializes \tcode{sb} from \tcode{buf} and \tcode{allocator}. -Initializes the base class with \tcode{basic_ostream(addressof(sb))}. +Initializes \exposid{sb} from \tcode{buf} and \tcode{allocator}. +Initializes the base class with \tcode{basic_ostream(addressof(\exposid{sb}))}. \pnum \begin{note} @@ -12905,8 +13026,8 @@ \pnum \effects Move constructs the base class -and \tcode{sb} from the corresponding subobjects of \tcode{other}, -and calls \tcode{basic_ostream::set_rdbuf(addressof(sb))}. +and \exposid{sb} from the corresponding subobjects of \tcode{other}, +and calls \tcode{basic_ostream::set_rdbuf(addressof(\exposid{sb}))}. \pnum \ensures @@ -12927,7 +13048,7 @@ \pnum \effects Behaves as an unformatted output function\iref{ostream.unformatted}. -After constructing a \tcode{sentry} object, calls \tcode{sb.emit()}. +After constructing a \tcode{sentry} object, calls \tcode{\exposid{sb}.emit()}. If that call returns \tcode{false}, calls \tcode{setstate(ios_base::badbit)}. @@ -12972,7 +13093,7 @@ \begin{itemdescr} \pnum \returns -\tcode{sb.get_wrapped()}. +\tcode{\exposid{sb}.get_wrapped()}. \pnum \begin{example} @@ -13358,8 +13479,11 @@ path weakly_canonical(const path& p, error_code& ec); } -// \ref{fs.path.hash}, hash support namespace std { + // \ref{fs.path.fmtr}, formatting support + template struct formatter; + + // \ref{fs.path.hash}, hash support template struct hash; template<> struct hash; } @@ -13494,7 +13618,8 @@ a pathname to a particular file in a file hierarchy. There may be multiple pathnames that resolve to the same file. \begin{example} -POSIX specifies the mechanism in section 4.12, Pathname resolution. +For POSIX-based operating systems, +this mechanism is specified in POSIX, section 4.12, Pathname resolution. \end{example} \begin{codeblock} @@ -13616,7 +13741,7 @@ path extension() const; // \ref{fs.path.query}, query - [[nodiscard]] bool empty() const noexcept; + bool empty() const noexcept; bool has_root_name() const; bool has_root_directory() const; bool has_root_path() const; @@ -13838,8 +13963,8 @@ \begin{note} Some operating systems have no unambiguous way to distinguish between native format and generic format arguments. This is by design as it simplifies use for operating systems that do not require -disambiguation. An implementation for an operating system where disambiguation -is required is permitted to distinguish between the formats. +disambiguation. It is possible that an implementation for an operating system +where disambiguation is needed distinguishes between the formats. \end{note} \pnum @@ -13963,14 +14088,14 @@ \item \tcode{basic_string_view}. A function argument \tcode{const Source\&} \tcode{source} shall have an effective range \range{source.begin()}{source.end()}. -\item A type meeting the \oldconcept{InputIterator} requirements that iterates over a NTCTS\@. +\item A type meeting the \oldconcept{InputIterator} requirements that iterates over an NTCTS\@. The value type shall be an encoded character type. A function argument \tcode{const Source\&} \tcode{source} shall have an effective range \range{source}{end} where \tcode{end} is the first iterator value with an element value equal to \tcode{iterator_traits::value_type()}. \item A character array that after array-to-pointer decay results in a - pointer to the start of a NTCTS\@. The value type shall be an encoded character type. A + pointer to the start of an NTCTS\@. The value type shall be an encoded character type. A function argument \tcode{const Source\&} \tcode{source} shall have an effective range \range{source}{end} where \tcode{end} is the first iterator value with an element value equal to @@ -14383,7 +14508,7 @@ \effects Each \grammarterm{directory-separator} of the pathname in the generic format - is converted to \grammarterm{preferred-separator}. +is converted to \grammarterm{preferred-separator}. \pnum \returns @@ -14862,7 +14987,7 @@ \indexlibrarymember{empty}{path}% \begin{itemdecl} -[[nodiscard]] bool empty() const noexcept; +bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -15160,8 +15285,8 @@ \item The \grammarterm{root-name} element, if present. \item The \grammarterm{root-directory} element, if present. \begin{note} -The generic format is required to ensure lexicographical -comparison works correctly. +It is possible that the use of the generic format is needed +to ensure correct lexicographical comparison. \end{note} \item Each successive \grammarterm{filename} element, if present. \item An empty element, if a trailing non-root \grammarterm{directory-separator} @@ -15314,6 +15439,102 @@ Equivalent to: \tcode{return path(lhs) /= rhs;} \end{itemdescr} +\rSec3[fs.path.fmtr]{Formatting support} + +\rSec4[fs.path.fmtr.general]{Formatting support overview} + +\indexlibraryglobal{formatter}% +\begin{codeblock} +namespace std { + template struct formatter { + constexpr void set_debug_format(); + + constexpr typename basic_format_parse_context::iterator + parse(basic_format_parse_context& ctx); + + template + typename FormatContext::iterator + format(const filesystem::path& path, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\rSec4[fs.path.fmtr.funcs]{Formatting support functions} + +\pnum +Formatting of paths uses formatting specifiers of the form +\begin{ncbnf} +\nontermdef{path-format-spec}\br + \opt{fill-and-align} \opt{width} \opt{\terminal{?}} \opt{\terminal{g}} +\end{ncbnf} +where the productions \fmtgrammarterm{fill-and-align} and \fmtgrammarterm{width} +are described in \ref{format.string}. +If the \tcode{?} option is used then +the path is formatted as an escaped string\iref{format.string.escaped}. + +\indexlibrarymember{formatter}{set_debug_format}% +\begin{itemdecl} +constexpr void set_debug_format(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Modifies the state of the \tcode{formatter} to be as if +the \fmtgrammarterm{path-format-spec} parsed by the last call to \tcode{parse} +contained the \tcode{?} option. +\end{itemdescr} + +\indexlibrarymember{formatter}{basic_format_parse_context}% +\begin{itemdecl} +constexpr typename basic_format_parse_context::iterator + parse(basic_format_parse_context& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Parses the format specifier as a \fmtgrammarterm{path-format-spec} and +stores the parsed specifiers in \tcode{*this}. + +\pnum +\returns +An iterator past the end of the \fmtgrammarterm{path-format-spec}. +\end{itemdescr} + +\indexlibrarymember{formatter}{format}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(const filesystem::path& p, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Let \tcode{s} be \tcode{p.generic_string()} +if the \tcode{g} option is used, +otherwise \tcode{p.native()}. +Writes \tcode{s} into \tcode{ctx.out()}, +adjusted according to the \fmtgrammarterm{path-format-spec}. +If \tcode{charT} is \keyword{char}, +\tcode{path::value_type} is \keyword{wchar_t}, and +the literal encoding is UTF-8, +then the escaped path is transcoded from the native encoding for +wide character strings to UTF-8 with +maximal subparts of ill-formed subsequences +substituted with \ucode{fffd} \uname{replacement character} +per the Unicode Standard, Chapter 3.9 \ucode{fffd} Substitution in Conversion. +If \tcode{charT} and \tcode{path::value_type} are the same +then no transcoding is performed. +Otherwise, transcoding is +\impldef{transcoding of a formatted path when \tcode{charT} and \tcode{path::value_type} differ}. + +\pnum +\returns +An iterator past the end of the output range. +\end{itemdescr} + \rSec3[fs.path.hash]{Hash support} \begin{itemdecl} @@ -15489,10 +15710,10 @@ \lhdr{Constant} & \rhdr{Meaning} \\ \capsep -\tcode{none} & +\tcode{\libmember{none}{file_type}} & The type of the file has not been determined or an error occurred while trying to determine the type. \\ \rowsep -\tcode{not_found} & +\tcode{\libmember{not_found}{file_type}} & Pseudo-type indicating the file was not found. \begin{tailnote} The file @@ -15500,13 +15721,13 @@ type of a file. \end{tailnote} \\ \rowsep -\tcode{regular} & Regular file \\ \rowsep -\tcode{directory} & Directory file \\ \rowsep -\tcode{symlink} & Symbolic link file \\ \rowsep -\tcode{block} & Block special file \\ \rowsep -\tcode{character} & Character special file \\ \rowsep -\tcode{fifo} & FIFO or pipe file \\ \rowsep -\tcode{socket} & Socket file \\ \rowsep +\tcode{\libmember{regular}{file_type}} & Regular file \\ \rowsep +\tcode{\libmember{directory}{file_type}} & Directory file \\ \rowsep +\tcode{\libmember{symlink}{file_type}} & Symbolic link file \\ \rowsep +\tcode{\libmember{block}{file_type}} & Block special file \\ \rowsep +\tcode{\libmember{character}{file_type}} & Character special file \\ \rowsep +\tcode{\libmember{fifo}{file_type}} & FIFO or pipe file \\ \rowsep +\tcode{\libmember{socket}{file_type}} & Socket file \\ \rowsep \tcode{\textit{\impldef{additional \tcode{file_type} enumerators for file systems supporting additional types of file}}} & Implementations that support file systems having file types @@ -15516,7 +15737,7 @@ for file systems supporting additional types of file} \tcode{file_type} constants to separately identify each of those additional file types \\ \rowsep -\tcode{unknown} & +\tcode{\libmember{unknown}{file_type}} & The file exists but the type cannot be determined \\ \end{floattable} @@ -15538,42 +15759,42 @@ \topline \ohdrx{2}{Option group controlling \tcode{copy_file} function effects for existing target files} \\ \rowsep \lhdr{Constant} & \rhdr{Meaning} \\ \capsep -\tcode{none} & +\tcode{\libmember{none}{copy_options}} & (Default) Error; file already exists. \\ \rowsep -\tcode{skip_existing} & +\tcode{\libmember{skip_existing}{copy_options}} & Do not overwrite existing file, do not report an error. \\ \rowsep -\tcode{overwrite_existing} & +\tcode{\libmember{overwrite_existing}{copy_options}} & Overwrite the existing file. \\ \rowsep -\tcode{update_existing} & +\tcode{\libmember{update_existing}{copy_options}} & Overwrite the existing file if it is older than the replacement file. \\ \capsep \ohdrx{2}{Option group controlling \tcode{copy} function effects for subdirectories} \\ \rowsep \lhdr{Constant} & \rhdr{Meaning} \\ \capsep -\tcode{none} & +\tcode{\libmember{none}{copy_options}} & (Default) Do not copy subdirectories. \\ \rowsep -\tcode{recursive} & +\tcode{\libmember{recursive}{copy_options}} & Recursively copy subdirectories and their contents. \\ \capsep \ohdrx{2}{Option group controlling \tcode{copy} function effects for symbolic links} \\ \rowsep \lhdr{Constant} & \rhdr{Meaning} \\ \capsep -\tcode{none} & +\tcode{\libmember{none}{copy_options}} & (Default) Follow symbolic links. \\ \rowsep -\tcode{copy_symlinks} & +\tcode{\libmember{copy_symlinks}{copy_options}} & Copy symbolic links as symbolic links rather than copying the files that they point to. \\ \rowsep -\tcode{skip_symlinks} & +\tcode{\libmember{skip_symlinks}{copy_options}} & Ignore symbolic links. \\ \capsep \ohdrx{2}{Option group controlling \tcode{copy} function effects for choosing the form of copying} \\ \rowsep \lhdr{Constant} & \rhdr{Meaning} \\ \capsep -\tcode{none} & +\tcode{\libmember{none}{copy_options}} & (Default) Copy content. \\ \rowsep -\tcode{directories_only} & +\tcode{\libmember{directories_only}{copy_options}} & Copy directory structure only, do not copy non-directory files. \\ \rowsep -\tcode{create_symlinks} & +\tcode{\libmember{create_symlinks}{copy_options}} & Make symbolic links instead of copies of files. The source path shall be an absolute path unless the destination path is in the current directory. \\ \rowsep -\tcode{create_hard_links} & +\tcode{\libmember{create_hard_links}{copy_options}} & Make hard links instead of copies of files. \\ \end{floattable} @@ -15592,46 +15813,46 @@ \lhdr{Name} & \chdr{Value} & \chdr{POSIX} & \rhdr{Definition or notes} \\ & \chdr{(octal)} & \chdr{macro} & \\ \capsep -\tcode{none} & \tcode{0} & & +\tcode{\libmember{none}{perms}} & \tcode{0} & & There are no permissions set for the file. \\ \rowsep -\tcode{owner_read} & \tcode{0400} & \tcode{S_IRUSR} & +\tcode{\libmember{owner_read}{perms}} & \tcode{0400} & \tcode{S_IRUSR} & Read permission, owner \\ \rowsep -\tcode{owner_write} & \tcode{0200} & \tcode{S_IWUSR} & +\tcode{\libmember{owner_write}{perms}} & \tcode{0200} & \tcode{S_IWUSR} & Write permission, owner \\ \rowsep -\tcode{owner_exec} & \tcode{0100} & \tcode{S_IXUSR} & +\tcode{\libmember{owner_exec}{perms}} & \tcode{0100} & \tcode{S_IXUSR} & Execute/search permission, owner \\ \rowsep -\tcode{owner_all} & \tcode{0700} & \tcode{S_IRWXU} & +\tcode{\libmember{owner_all}{perms}} & \tcode{0700} & \tcode{S_IRWXU} & Read, write, execute/search by owner;\br \tcode{owner_read | owner_write | owner_exec} \\ \rowsep -\tcode{group_read} & \tcode{040} & \tcode{S_IRGRP} & +\tcode{\libmember{group_read}{perms}} & \tcode{040} & \tcode{S_IRGRP} & Read permission, group \\ \rowsep -\tcode{group_write} & \tcode{020} & \tcode{S_IWGRP} & +\tcode{\libmember{group_write}{perms}} & \tcode{020} & \tcode{S_IWGRP} & Write permission, group \\ \rowsep -\tcode{group_exec} & \tcode{010} & \tcode{S_IXGRP} & +\tcode{\libmember{group_exec}{perms}} & \tcode{010} & \tcode{S_IXGRP} & Execute/search permission, group \\ \rowsep -\tcode{group_all} & \tcode{070} & \tcode{S_IRWXG} & +\tcode{\libmember{group_all}{perms}} & \tcode{070} & \tcode{S_IRWXG} & Read, write, execute/search by group;\br \tcode{group_read | group_write | group_exec} \\ \rowsep -\tcode{others_read} & \tcode{04} & \tcode{S_IROTH} & +\tcode{\libmember{others_read}{perms}} & \tcode{04} & \tcode{S_IROTH} & Read permission, others \\ \rowsep -\tcode{others_write} & \tcode{02} & \tcode{S_IWOTH} & +\tcode{\libmember{others_write}{perms}} & \tcode{02} & \tcode{S_IWOTH} & Write permission, others \\ \rowsep -\tcode{others_exec} & \tcode{01} & \tcode{S_IXOTH} & +\tcode{\libmember{others_exec}{perms}} & \tcode{01} & \tcode{S_IXOTH} & Execute/search permission, others \\ \rowsep -\tcode{others_all} & \tcode{07} & \tcode{S_IRWXO} & +\tcode{\libmember{others_all}{perms}} & \tcode{07} & \tcode{S_IRWXO} & Read, write, execute/search by others;\br \tcode{others_read | others_write | others_exec} \\ \rowsep -\tcode{all} & \tcode{0777} & & +\tcode{\libmember{all}{perms}} & \tcode{0777} & & \tcode{owner_all | group_all | others_all} \\ \rowsep -\tcode{set_uid} & \tcode{04000} & \tcode{S_ISUID} & +\tcode{\libmember{set_uid}{perms}} & \tcode{04000} & \tcode{S_ISUID} & Set-user-ID on execution \\ \rowsep -\tcode{set_gid} & \tcode{02000} & \tcode{S_ISGID} & +\tcode{\libmember{set_gid}{perms}} & \tcode{02000} & \tcode{S_ISGID} & Set-group-ID on execution \\ \rowsep -\tcode{sticky_bit} & \tcode{01000} & \tcode{S_ISVTX} & +\tcode{\libmember{sticky_bit}{perms}} & \tcode{01000} & \tcode{S_ISVTX} & Operating system dependent. \\ \rowsep -\tcode{mask} & \tcode{07777} & & +\tcode{\libmember{mask}{perms}} & \tcode{07777} & & \tcode{all | set_uid | set_gid | sticky_bit} \\ \rowsep -\tcode{unknown} & \tcode{0xFFFF} & & +\tcode{\libmember{unknown}{perms}} & \tcode{0xFFFF} & & The permissions are not known, such as when a \tcode{file_status} object is created without specifying the permissions \\ \end{floattable} @@ -15653,15 +15874,15 @@ \topline \lhdr{Name} & \rhdr{Meaning} \\ \capsep -\tcode{replace} & +\tcode{\libmember{replace}{perm_options}} & \tcode{permissions} shall replace the file's permission bits with \tcode{perm} \\ \rowsep -\tcode{add} & +\tcode{\libmember{add}{perm_options}} & \tcode{permissions} shall replace the file's permission bits with the bitwise \logop{or} of \tcode{perm} and the file's current permission bits. \\ \rowsep -\tcode{remove} & +\tcode{\libmember{remove}{perm_options}} & \tcode{permissions} shall replace the file's permission bits with the bitwise \logop{and} of the complement of \tcode{perm} and the file's current permission bits. \\ \rowsep -\tcode{nofollow} & +\tcode{\libmember{nofollow}{perm_options}} & \tcode{permissions} shall change the permissions of a symbolic link itself rather than the permissions of the file the link resolves to. \\ \end{floattable} @@ -15684,11 +15905,11 @@ \lhdr{Name} & \rhdr{Meaning} \\ \capsep -\tcode{none} & +\tcode{\libmember{none}{directory_options}} & (Default) Skip directory symlinks, permission denied is an error. \\ \rowsep -\tcode{follow_directory_symlink} & +\tcode{\libmember{follow_directory_symlink}{directory_options}} & Follow rather than skip directory symlinks. \\ \rowsep -\tcode{skip_permission_denied} & +\tcode{\libmember{skip_permission_denied}{directory_options}} & Skip directories that would otherwise result in permission denied. \\ \end{floattable} @@ -15863,8 +16084,7 @@ operator<<(basic_ostream& os, const directory_entry& d); private: - filesystem::path pathobject; // \expos - friend class directory_iterator; // \expos + filesystem::path @\exposid{path-object}@; // \expos }; } \end{codeblock} @@ -15883,13 +16103,10 @@ \pnum \begin{note} -For purposes of exposition, -class \tcode{directory_iterator}\iref{fs.class.directory.iterator} -is shown above as a friend of class \tcode{directory_entry}. -Friendship allows the \tcode{directory_iterator} implementation to cache +\tcode{directory_iterator} can cache already available attribute values directly into a \tcode{directory_entry} object -without the cost of an unneeded call to \tcode{refresh()}. +without the cost of a call to \tcode{refresh()}. \end{note} \pnum @@ -15958,7 +16175,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to \tcode{pathobject = p}, +Equivalent to \tcode{\exposid{path-object} = p}, then \tcode{refresh()} or \tcode{refresh(ec)}, respectively. If an error occurs, the values of any cached attributes are unspecified. @@ -15976,7 +16193,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to \tcode{pathobject.replace_filename(p)}, +Equivalent to \tcode{\exposid{path-object}.replace_filename(p)}, then \tcode{refresh()} or \tcode{refresh(ec)}, respectively. If an error occurs, the values of any cached attributes are unspecified. @@ -16027,7 +16244,7 @@ \begin{itemdescr} \pnum \returns -\tcode{pathobject}. +\exposid{path-object}. \end{itemdescr} \indexlibrarymember{exists}{directory_entry}% @@ -16267,7 +16484,7 @@ \begin{itemdescr} \pnum \returns -\tcode{pathobject == rhs.pathobject}. +\tcode{\exposid{path-object} == rhs.\exposid{path-object}}. \end{itemdescr} \indexlibrarymember{operator<=>}{directory_entry}% @@ -16278,7 +16495,7 @@ \begin{itemdescr} \pnum \returns -\tcode{pathobject <=> rhs.pathobject}. +\tcode{\exposid{path-object} <=> rhs.\exposid{path-object}}. \end{itemdescr} \rSec3[fs.dir.entry.io]{Inserter} @@ -16388,8 +16605,6 @@ any \tcode{directory_entry} \tcode{refresh} function. \begin{note} The exact mechanism for storing cached attribute values is not exposed to users. -For exposition, class \tcode{directory_iterator} is shown in \ref{fs.class.directory.entry} -as a friend of class \tcode{directory_entry}. \end{note} \pnum @@ -16879,7 +17094,7 @@ \pnum \begin{note} -\tcode{disable_recursion_pending}\tcode{()} is used to prevent +\tcode{disable_recursion_pending()} is used to prevent unwanted recursion into a directory. \end{note} \end{itemdescr} @@ -17074,7 +17289,7 @@ \impldef{effect of \tcode{filesystem::copy}}. \item -Otherwise, an error is reported as specified in~\ref{fs.err.report} if: +Otherwise, an error is reported as specified in~\ref{fs.err.report} if \begin{itemize} \item \tcode{exists(f)} is \tcode{false}, or \item \tcode{equivalent(from, to)} is \tcode{true}, or @@ -17157,16 +17372,16 @@ \pnum \begin{example} Given this directory structure: -\begin{codeblock} +\begin{outputblock} /dir1 file1 file2 dir2 file3 -\end{codeblock} +\end{outputblock} Calling \tcode{copy("/dir1", "/dir3")} would result in: -\begin{codeblock} +\begin{outputblock} /dir1 file1 file2 @@ -17175,10 +17390,10 @@ /dir3 file1 file2 -\end{codeblock} +\end{outputblock} Alternatively, calling \tcode{copy("/dir1", "/dir3", copy_options::recursive)} would result in: -\begin{codeblock} +\begin{outputblock} /dir1 file1 file2 @@ -17189,7 +17404,7 @@ file2 dir2 file3 -\end{codeblock} +\end{outputblock} \end{example} \end{itemdescr} @@ -17232,7 +17447,7 @@ As follows: \begin{itemize} \item -Report an error as specified in~\ref{fs.err.report} if: +Report an error as specified in~\ref{fs.err.report} if \begin{itemize} \item \tcode{is_regular_file(from)} is \tcode{false}, or \item \tcode{exists(to)} is \tcode{true} and \tcode{is_regular_file(to)} is \tcode{false}, or @@ -17247,7 +17462,7 @@ \item Otherwise, copy the contents and attributes of the file \tcode{from} - resolves to, to the file \tcode{to} resolves to, if: + resolves to, to the file \tcode{to} resolves to, if \begin{itemize} \item \tcode{exists(to)} is \tcode{false}, or \item \tcode{(options \& copy_options::overwrite_existing) != copy_options::none}, or @@ -17309,7 +17524,7 @@ \begin{itemdescr} \pnum \effects -Calls \tcode{create_directory()} for each element of \tcode{p} +Calls \tcode{create_directory} for each element of \tcode{p} that does not exist. \pnum @@ -17402,7 +17617,7 @@ \begin{itemdescr} \pnum \effects -Establishes the postcondition, as if by POSIX \tcode{symlink()}. +Establishes the postcondition, as if by POSIX \tcode{symlink}. \pnum \ensures @@ -17417,7 +17632,7 @@ \begin{note} Some operating systems require symlink creation to identify that the link is to a directory. -Thus, \tcode{create_symlink()} (instead of \tcode{create_directory_symlink()}) +Thus, \tcode{create_symlink} (instead of \tcode{create_directory_symlink}) cannot be used reliably to create directory symlinks. \end{note} @@ -17443,7 +17658,7 @@ \begin{itemdescr} \pnum \effects -Establishes the postcondition, as if by POSIX \tcode{link()}. +Establishes the postcondition, as if by POSIX \tcode{link}. \pnum \ensures @@ -17478,7 +17693,7 @@ \begin{itemdescr} \pnum \effects -Establishes the postcondition, as if by POSIX \tcode{symlink()}. +Establishes the postcondition, as if by POSIX \tcode{symlink}. \pnum \ensures @@ -17511,7 +17726,7 @@ \returns The absolute path of the current working directory, whose pathname in the native format is - obtained as if by POSIX \tcode{getcwd()}. + obtained as if by POSIX \tcode{getcwd}. The signature with argument \tcode{ec} returns \tcode{path()} if an error occurs. @@ -17525,12 +17740,6 @@ with the process, that is used as the starting location in pathname resolution for relative paths. -\pnum -\begin{note} -The \tcode{current_path()} name was chosen to emphasize that the returned value is a - path, not just a single directory name. -\end{note} - \pnum \begin{note} The current path as returned by many operating systems is a dangerous @@ -17548,7 +17757,7 @@ \begin{itemdescr} \pnum \effects -Establishes the postcondition, as if by POSIX \tcode{chdir()}. +Establishes the postcondition, as if by POSIX \tcode{chdir}. \pnum \ensures @@ -17581,7 +17790,7 @@ \begin{note} On POSIX platforms, this is determined as if by the values of the POSIX \tcode{stat} class, - obtained as if by \tcode{stat()} for the two paths, having equal \tcode{st_dev} values + obtained as if by \tcode{stat} for the two paths, having equal \tcode{st_dev} values and equal \tcode{st_ino} values. \end{note} @@ -17659,7 +17868,7 @@ \item If \tcode{is_regular_file(p)}, the size in bytes of the file \tcode{p} resolves to, determined as if by the value of the POSIX \tcode{stat} - class member \tcode{st_size} obtained as if by POSIX \tcode{stat()}. + class member \tcode{st_size} obtained as if by POSIX \tcode{stat}. \item Otherwise, the result is \impldef{result of \tcode{filesystem::file_size}}. \end{itemize} @@ -18021,7 +18230,7 @@ \returns The time of last data modification of \tcode{p}, determined as if by the value of the POSIX \tcode{stat} class member \tcode{st_mtime} - obtained as if by POSIX \tcode{stat()}. + obtained as if by POSIX \tcode{stat}. The signature with argument \tcode{ec} returns \tcode{file_time_type::min()} if an error occurs. @@ -18041,7 +18250,7 @@ \pnum \effects Sets the time of last data modification of the file - resolved to by \tcode{p} to \tcode{new_time}, as if by POSIX \tcode{futimens()}. + resolved to by \tcode{p} to \tcode{new_time}, as if by POSIX \tcode{futimens}. \pnum \throws @@ -18075,7 +18284,7 @@ to the file \tcode{p} resolves to, or to file \tcode{p} itself if \tcode{p} is a symbolic link and \tcode{perm_options::nofollow} is set in \tcode{opts}. -The action is applied as if by POSIX \tcode{fchmodat()}. +The action is applied as if by POSIX \tcode{fchmodat}. \pnum \begin{note} @@ -18212,7 +18421,7 @@ \pnum \effects If \tcode{exists(symlink_status(p, ec))}, the file \tcode{p} is - removed as if by POSIX \tcode{remove()}. + removed as if by POSIX \tcode{remove}. \begin{note} A symbolic link is itself removed, rather than the file it resolves to. @@ -18224,9 +18433,10 @@ \pnum \returns -\tcode{false} if \tcode{p} did not exist, - otherwise \tcode{true}. The signature with argument \tcode{ec} - returns \tcode{false} if an error occurs. +\tcode{true} if a file \tcode{p} has been removed and \tcode{false} otherwise. +\begin{note} +Absence of a file \tcode{p} is not an error. +\end{note} \pnum \throws @@ -18246,7 +18456,7 @@ \pnum \effects Recursively deletes the contents of \tcode{p} if it exists, - then deletes file \tcode{p} itself, as if by POSIX \tcode{remove()}. + then deletes file \tcode{p} itself, as if by POSIX \tcode{remove}. \begin{note} A symbolic link is itself removed, rather than the file it resolves to. @@ -18280,7 +18490,7 @@ \pnum \effects Renames \tcode{old_p} to \tcode{new_p}, as if by - POSIX \tcode{rename()}. + POSIX \tcode{rename}. \begin{note} \begin{itemize} @@ -18316,7 +18526,7 @@ \pnum \effects Causes the size that would be returned by \tcode{file_size(p)} to be -equal to \tcode{new_size}, as if by POSIX \tcode{truncate()}. +equal to \tcode{new_size}, as if by POSIX \tcode{truncate}. \pnum \throws @@ -18371,7 +18581,7 @@ \begin{itemdescr} \pnum \effects -As if: +As if by: \begin{codeblock} error_code ec; file_status result = status(p, ec); @@ -18403,14 +18613,14 @@ \pnum \effects If possible, determines the attributes - of the file \tcode{p} resolves to, as if by using POSIX \tcode{stat()} + of the file \tcode{p} resolves to, as if by using POSIX \tcode{stat} to obtain a POSIX \tcode{struct stat}. If, during attribute determination, the underlying file system API reports an error, sets \tcode{ec} to indicate the specific error reported. Otherwise, \tcode{ec.clear()}. \begin{note} This allows users to inspect the specifics of underlying - API errors even when the value returned by \tcode{status()} is not + API errors even when the value returned by \tcode{status} is not \tcode{file_status(file_type::none)}. \end{note} @@ -18504,9 +18714,9 @@ \begin{itemdescr} \pnum \effects -Same as \tcode{status()}, above, +Same as \tcode{status}, above, except that the attributes - of \tcode{p} are determined as if by using POSIX \tcode{lstat()} + of \tcode{p} are determined as if by using POSIX \tcode{lstat} to obtain a POSIX \tcode{struct stat}. \pnum @@ -18516,7 +18726,7 @@ \pnum \returns -Same as \tcode{status()}, above, except +Same as \tcode{status}, above, except that if the attributes indicate a symbolic link, as if by POSIX \tcode{S_ISLNK}, returns \tcode{file_status(file_type::symlink, prms)}. The signature with argument \tcode{ec} returns @@ -18585,14 +18795,14 @@ Using \tcode{status(p)} or \tcode{status(p, ec)}, respectively, to determine existence, return a path composed by \tcode{operator/=} - from the result of calling \tcode{canonical()} + from the result of calling \tcode{canonical} with a path argument composed of the leading elements of \tcode{p} that exist, if any, followed by the elements of \tcode{p} that do not exist, if any. For the first form, - \tcode{canonical()} is called without an \tcode{error_code} argument. + \tcode{canonical} is called without an \tcode{error_code} argument. For the second form, - \tcode{canonical()} is called + \tcode{canonical} is called with \tcode{ec} as an \tcode{error_code} argument, and \tcode{path()} is returned at the first error occurrence, if any. @@ -18618,22 +18828,6 @@ \indexlibraryglobal{size_t}% \indexlibraryglobal{FILE}% \indexlibraryglobal{fpos_t}% -\indexlibraryglobal{NULL}% -\indexlibraryglobal{_IOFBF}% -\indexlibraryglobal{_IOLBF}% -\indexlibraryglobal{_IONBF}% -\indexlibraryglobal{BUFSIZ}% -\indexlibraryglobal{EOF}% -\indexlibraryglobal{FOPEN_MAX}% -\indexlibraryglobal{FILENAME_MAX}% -\indexlibraryglobal{L_tmpnam}% -\indexlibraryglobal{SEEK_CUR}% -\indexlibraryglobal{SEEK_END}% -\indexlibraryglobal{SEEK_SET}% -\indexlibraryglobal{TMP_MAX}% -\indexlibraryglobal{stderr}% -\indexlibraryglobal{stdin}% -\indexlibraryglobal{stdout}% \indexlibraryglobal{remove}% \indexlibraryglobal{rename}% \indexlibraryglobal{tmpfile}% @@ -18686,22 +18880,22 @@ using fpos_t = @\seebelow@; } -#define NULL @\textit{see \ref{support.types.nullptr}}@ -#define _IOFBF @\seebelow@ -#define _IOLBF @\seebelow@ -#define _IONBF @\seebelow@ -#define BUFSIZ @\seebelow@ -#define EOF @\seebelow@ -#define FOPEN_MAX @\seebelow@ -#define FILENAME_MAX @\seebelow@ -#define L_tmpnam @\seebelow@ -#define SEEK_CUR @\seebelow@ -#define SEEK_END @\seebelow@ -#define SEEK_SET @\seebelow@ -#define TMP_MAX @\seebelow@ -#define stderr @\seebelow@ -#define stdin @\seebelow@ -#define stdout @\seebelow@ +#define @\libmacro{NULL}@ @\textit{see \ref{support.types.nullptr}}@ +#define @\libmacro{_IOFBF}@ @\seebelow@ +#define @\libmacro{_IOLBF}@ @\seebelow@ +#define @\libmacro{_IONBF}@ @\seebelow@ +#define @\libmacro{BUFSIZ}@ @\seebelow@ +#define @\libmacro{EOF}@ @\seebelow@ +#define @\libmacro{FOPEN_MAX}@ @\seebelow@ +#define @\libmacro{FILENAME_MAX}@ @\seebelow@ +#define @\libmacro{L_tmpnam}@ @\seebelow@ +#define @\libmacro{SEEK_CUR}@ @\seebelow@ +#define @\libmacro{SEEK_END}@ @\seebelow@ +#define @\libmacro{SEEK_SET}@ @\seebelow@ +#define @\libmacro{TMP_MAX}@ @\seebelow@ +#define @\libmacro{stderr}@ @\seebelow@ +#define @\libmacro{stdin}@ @\seebelow@ +#define @\libmacro{stdout}@ @\seebelow@ namespace std { int remove(const char* filename); @@ -18756,6 +18950,13 @@ The contents and meaning of the header \libheader{cstdio} are the same as the C standard library header \libheader{stdio.h}. +\pnum +The return from each function call +that delivers data +to the host environment +to be written to a file (\xrefc{7.21.3}) +is an observable checkpoint\iref{intro.abstract}. + \pnum Calls to the function \tcode{tmpnam} with an argument that is a null pointer value may introduce a data race\iref{res.on.data.races} with other calls to \tcode{tmpnam} with @@ -18808,28 +19009,6 @@ \indexlibraryglobal{SCNoFASTN}% \indexlibraryglobal{SCNuFASTN}% \indexlibraryglobal{SCNxFASTN}% -\indexlibraryglobal{PRIdMAX}% -\indexlibraryglobal{PRIiMAX}% -\indexlibraryglobal{PRIoMAX}% -\indexlibraryglobal{PRIuMAX}% -\indexlibraryglobal{PRIxMAX}% -\indexlibraryglobal{PRIXMAX}% -\indexlibraryglobal{SCNdMAX}% -\indexlibraryglobal{SCNiMAX}% -\indexlibraryglobal{SCNoMAX}% -\indexlibraryglobal{SCNuMAX}% -\indexlibraryglobal{SCNxMAX}% -\indexlibraryglobal{PRIdPTR}% -\indexlibraryglobal{PRIiPTR}% -\indexlibraryglobal{PRIoPTR}% -\indexlibraryglobal{PRIuPTR}% -\indexlibraryglobal{PRIxPTR}% -\indexlibraryglobal{PRIXPTR}% -\indexlibraryglobal{SCNdPTR}% -\indexlibraryglobal{SCNiPTR}% -\indexlibraryglobal{SCNoPTR}% -\indexlibraryglobal{SCNuPTR}% -\indexlibraryglobal{SCNxPTR}% \begin{codeblock} #include // see \ref{cstdint.syn} @@ -18880,28 +19059,28 @@ #define SCNoFAST@\placeholdernc{N}@ @\seebelow@ #define SCNuFAST@\placeholdernc{N}@ @\seebelow@ #define SCNxFAST@\placeholdernc{N}@ @\seebelow@ -#define PRIdMAX @\seebelow@ -#define PRIiMAX @\seebelow@ -#define PRIoMAX @\seebelow@ -#define PRIuMAX @\seebelow@ -#define PRIxMAX @\seebelow@ -#define PRIXMAX @\seebelow@ -#define SCNdMAX @\seebelow@ -#define SCNiMAX @\seebelow@ -#define SCNoMAX @\seebelow@ -#define SCNuMAX @\seebelow@ -#define SCNxMAX @\seebelow@ -#define PRIdPTR @\seebelow@ -#define PRIiPTR @\seebelow@ -#define PRIoPTR @\seebelow@ -#define PRIuPTR @\seebelow@ -#define PRIxPTR @\seebelow@ -#define PRIXPTR @\seebelow@ -#define SCNdPTR @\seebelow@ -#define SCNiPTR @\seebelow@ -#define SCNoPTR @\seebelow@ -#define SCNuPTR @\seebelow@ -#define SCNxPTR @\seebelow@ +#define @\libmacro{PRIdMAX}@ @\seebelow@ +#define @\libmacro{PRIiMAX}@ @\seebelow@ +#define @\libmacro{PRIoMAX}@ @\seebelow@ +#define @\libmacro{PRIuMAX}@ @\seebelow@ +#define @\libmacro{PRIxMAX}@ @\seebelow@ +#define @\libmacro{PRIXMAX}@ @\seebelow@ +#define @\libmacro{SCNdMAX}@ @\seebelow@ +#define @\libmacro{SCNiMAX}@ @\seebelow@ +#define @\libmacro{SCNoMAX}@ @\seebelow@ +#define @\libmacro{SCNuMAX}@ @\seebelow@ +#define @\libmacro{SCNxMAX}@ @\seebelow@ +#define @\libmacro{PRIdPTR}@ @\seebelow@ +#define @\libmacro{PRIiPTR}@ @\seebelow@ +#define @\libmacro{PRIoPTR}@ @\seebelow@ +#define @\libmacro{PRIuPTR}@ @\seebelow@ +#define @\libmacro{PRIxPTR}@ @\seebelow@ +#define @\libmacro{PRIXPTR}@ @\seebelow@ +#define @\libmacro{SCNdPTR}@ @\seebelow@ +#define @\libmacro{SCNiPTR}@ @\seebelow@ +#define @\libmacro{SCNoPTR}@ @\seebelow@ +#define @\libmacro{SCNuPTR}@ @\seebelow@ +#define @\libmacro{SCNxPTR}@ @\seebelow@ \end{codeblock} \pnum diff --git a/source/iterators.tex b/source/iterators.tex index b765432c95..d148a6489a 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -84,6 +84,7 @@ template concept indirectly_readable = @\seebelow@; // freestanding + // \ref{indirectcallable.traits}, indirect callable traits template<@\libconcept{indirectly_readable}@ T> using @\exposidnc{indirect-value-t}@ = @\seebelow@; // \expos @@ -168,10 +169,11 @@ // \ref{projected}, projected template<@\libconcept{indirectly_readable}@ I, @\libconcept{indirectly_regular_unary_invocable}@ Proj> - struct projected; // freestanding + using projected = @\seebelow@; // freestanding - template<@\libconcept{weakly_incrementable}@ I, class Proj> - struct incrementable_traits>; // freestanding + template<@\libconcept{indirectly_readable}@ I, @\libconcept{indirectly_regular_unary_invocable}@ Proj> + using projected_value_t = // freestanding + remove_cvref_t&>>; // \ref{alg.req}, common algorithm requirements // \ref{alg.req.ind.move}, concept \libconcept{indirectly_movable} @@ -202,7 +204,7 @@ // \ref{alg.req.mergeable}, concept \libconcept{mergeable} template + class R = ranges::less, class P1 = identity, class P2 = identity> concept mergeable = @\seebelow@; // freestanding // \ref{alg.req.sortable}, concept \libconcept{sortable} @@ -319,7 +321,7 @@ constexpr reverse_iterator make_reverse_iterator(Iterator i); // freestanding template - requires (!@\libconcept{sized_sentinel_for}@) + requires (!@\libconcept{sized_sentinel_for}@) constexpr bool @\libspec{disable_sized_sentinel_for}{reverse_iterator}@, // freestanding reverse_iterator> = true; @@ -409,7 +411,7 @@ constexpr move_iterator make_move_iterator(Iterator i); // freestanding template - requires (!@\libconcept{sized_sentinel_for}@) + requires (!@\libconcept{sized_sentinel_for}@) constexpr bool @\libspec{disable_sized_sentinel_for}{move_iterator}@, // freestanding move_iterator> = true; @@ -450,7 +452,7 @@ const istream_iterator& y); template> - class ostream_iterator; + class ostream_iterator; template> class istreambuf_iterator; @@ -498,11 +500,11 @@ template constexpr ptrdiff_t ssize(const T (&array)[N]) noexcept; // freestanding - template [[nodiscard]] constexpr auto + template constexpr auto empty(const C& c) -> decltype(c.empty()); // freestanding - template [[nodiscard]] constexpr bool + template constexpr bool empty(const T (&array)[N]) noexcept; // freestanding - template [[nodiscard]] constexpr bool + template constexpr bool empty(initializer_list il) noexcept; // freestanding template constexpr auto data(C& c) -> decltype(c.data()); // freestanding @@ -514,7 +516,7 @@ \rSec1[iterator.requirements]{Iterator requirements} -\rSec2[iterator.requirements.general]{In general} +\rSec2[iterator.requirements.general]{General} \pnum \indextext{requirements!iterator}% @@ -533,7 +535,7 @@ \defn{value type} of the iterator. An output iterator \tcode{i} has a non-empty set of types that are -\libconcept{indirectly_writable} to the iterator; +\defn{writable} to the iterator; for each such type \tcode{T}, the expression \tcode{*i = o} is valid where \tcode{o} is a value of type \tcode{T}. For every iterator type @@ -687,6 +689,24 @@ The result of the application of library functions to invalid ranges is undefined. +\pnum +For an iterator \tcode{i} of a type that +models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, +library functions are permitted +to replace \range{i}{s} with +\range{to_address(i)}{to_address(i + ranges::distance(i, s))}, and +to replace \countedrange{i}{n} with \range{to_address(i)}{to_address(i + n)}. +\begin{note} +This means a program cannot rely on any side effects of +dereferencing a contiguous iterator \tcode{i}, +because library functions might operate on +pointers obtained by \tcode{to_address(i)} +instead of operating on \tcode{i}. +Similarly, a program cannot rely on any side effects of +individual increments on a contiguous iterator \tcode{i}, +because library functions might advance \tcode{i} only once. +\end{note} + \pnum All the categories of iterators require only those functions that are realizable for a given category in constant time (amortized). @@ -709,12 +729,12 @@ \pnum \indextext{iterator!constexpr}% -Iterators are called \defn{constexpr iterators} +Iterators meet the \defn{constexpr iterator} requirements if all operations provided to meet iterator category requirements are constexpr functions. \begin{note} For example, the types ``pointer to \tcode{int}'' and -\tcode{reverse_iterator} are constexpr iterators. +\tcode{reverse_iterator} meet the constexpr iterator requirements. \end{note} \rSec2[iterator.assoc.types]{Associated types} @@ -1333,7 +1353,7 @@ \pnum Let \tcode{E} be 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{\libconcept{indirectly_writable}} only if +\tcode{Out} and \tcode{T} model \tcode{\libconcept{indirectly_writable}} only if: \begin{itemize} \item If \tcode{Out} and \tcode{T} model \tcode{\libconcept{indirectly_readable} \&\& \libconcept{same_as}, decay_t>}, @@ -1539,7 +1559,7 @@ \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 \defn{incrementable}. -\tcode{I} models \tcode{\libconcept{weakly_incrementable}} 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. \item If \tcode{i} is incrementable, then both \tcode{++i} @@ -1551,7 +1571,7 @@ \pnum \recommended -The implementaton of an algorithm on a weakly incrementable type +The implementation of an algorithm on a weakly incrementable type should never attempt to pass through the same incrementable value twice; such an algorithm should be a single-pass algorithm. \begin{note} @@ -1586,7 +1606,7 @@ \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)}. \item If \tcode{bool(a == b)} then \tcode{bool(((void)a++, a) == ++b)}. @@ -1649,7 +1669,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{\libconcept{sentinel_for}} only if +\tcode{S} and \tcode{I} model \tcode{\libconcept{sentinel_for}} only if: \begin{itemize} \item \tcode{i == s} is well-defined. @@ -1694,7 +1714,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{\libconcept{sized_sentinel_for}} 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}, then \tcode{s - i} is well-defined and equals $N$. @@ -1824,7 +1844,7 @@ \pnum Two dereferenceable iterators \tcode{a} and \tcode{b} of type \tcode{X} -offer the \defn{multi-pass guarantee} if: +offer the \defn{multi-pass guarantee} if \begin{itemize} \item \tcode{a == b} implies \tcode{++a == ++b} and \item the expression @@ -1913,7 +1933,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{random_access_iterator} only if +\tcode{I} models \libconcept{random_access_iterator} only if: \begin{itemize} \item \tcode{(a += n)} is equal to \tcode{b}. \item \tcode{addressof(a += n)} is equal to \tcode{addressof(a)}. @@ -1963,6 +1983,7 @@ \item \tcode{to_address(a) == addressof(*a)}, \item \tcode{to_address(b) == to_address(a) + D(b - a)}, \item \tcode{to_address(c) == to_address(a) + D(c - a)}, +\item \tcode{to_address(I\{\})} is well-defined, \item \tcode{ranges::iter_move(a)} has the same type, value category, and effects as \tcode{std::move(*a)}, and \item if \tcode{ranges::iter_swap(a, b)} is well-formed, @@ -2016,7 +2037,7 @@ bidirectional.iterators,random.access.iterators}. \pnum -A type \tcode{X} meets the \defnoldconcept{Iterator} requirements if: +A type \tcode{X} meets the \defnoldconcept{Iterator} requirements if \begin{itemize} \item \tcode{X} meets the \oldconcept{CopyConstructible}, \oldconcept{CopyAssignable}, \oldconcept{Swappable}, and \oldconcept{Destructible} requirements\iref{utility.arg.requirements,swappable.requirements}, and @@ -2241,7 +2262,7 @@ \pnum Two dereferenceable iterators \tcode{a} and \tcode{b} of type \tcode{X} offer the -\defn{multi-pass guarantee} if: +\defn{multi-pass guarantee} if \begin{itemize} \item \tcode{a == b} implies \tcode{++a == ++b} and \item \tcode{X} is a pointer type or the expression @@ -2444,7 +2465,6 @@ @\libconcept{copy_constructible}@ && @\libconcept{invocable}@> && @\libconcept{invocable}@> && - @\libconcept{invocable}@> && @\libconcept{common_reference_with}@< invoke_result_t>, invoke_result_t>>; @@ -2455,7 +2475,6 @@ @\libconcept{copy_constructible}@ && @\libconcept{regular_invocable}@> && @\libconcept{regular_invocable}@> && - @\libconcept{regular_invocable}@> && @\libconcept{common_reference_with}@< invoke_result_t>, invoke_result_t>>; @@ -2465,8 +2484,7 @@ @\libconcept{indirectly_readable}@ && @\libconcept{copy_constructible}@ && @\libconcept{predicate}@> && - @\libconcept{predicate}@> && - @\libconcept{predicate}@>; + @\libconcept{predicate}@>; template concept @\deflibconcept{indirect_binary_predicate}@ = @@ -2475,8 +2493,7 @@ @\libconcept{predicate}@, @\exposidnc{indirect-value-t}@> && @\libconcept{predicate}@, iter_reference_t> && @\libconcept{predicate}@, @\exposidnc{indirect-value-t}@> && - @\libconcept{predicate}@, iter_reference_t> && - @\libconcept{predicate}@, iter_common_reference_t>; + @\libconcept{predicate}@, iter_reference_t>; template concept @\deflibconcept{indirect_equivalence_relation}@ = @@ -2485,8 +2502,7 @@ @\libconcept{equivalence_relation}@, @\exposidnc{indirect-value-t}@> && @\libconcept{equivalence_relation}@, iter_reference_t> && @\libconcept{equivalence_relation}@, @\exposidnc{indirect-value-t}@> && - @\libconcept{equivalence_relation}@, iter_reference_t> && - @\libconcept{equivalence_relation}@, iter_common_reference_t>; + @\libconcept{equivalence_relation}@, iter_reference_t>; template concept @\deflibconcept{indirect_strict_weak_order}@ = @@ -2495,8 +2511,7 @@ @\libconcept{strict_weak_order}@, @\exposidnc{indirect-value-t}@> && @\libconcept{strict_weak_order}@, iter_reference_t> && @\libconcept{strict_weak_order}@, @\exposidnc{indirect-value-t}@> && - @\libconcept{strict_weak_order}@, iter_reference_t> && - @\libconcept{strict_weak_order}@, iter_common_reference_t>; + @\libconcept{strict_weak_order}@, iter_reference_t>; } \end{codeblock} @@ -2932,32 +2947,8 @@ \end{example} \pnum -The function templates defined in \ref{range.iter.ops} are not found by -argument-dependent name lookup\iref{basic.lookup.argdep}. When found by -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. - -\begin{example} -\begin{codeblock} -void foo() { - using namespace std::ranges; - std::vector vec{1,2,3}; - distance(begin(vec), end(vec)); // \#1 -} -\end{codeblock} -The function call expression at \tcode{\#1} invokes \tcode{std::ranges::distance}, -not \tcode{std::distance}, despite that -(a) the iterator type returned from \tcode{begin(vec)} and \tcode{end(vec)} -may be associated with namespace \tcode{std} and -(b) \tcode{std::distance} is more specialized\iref{temp.func.order} than -\tcode{std::ranges::distance} since the former requires its first two parameters -to have the same type. -\end{example} - -\pnum -The number and order of deducible template parameters for the function templates defined -in \ref{range.iter.ops} is unspecified, except where explicitly stated otherwise. +The entities defined in \ref{range.iter.ops} are +algorithm function objects\iref{alg.func.obj}. \rSec3[range.iter.op.advance]{\tcode{ranges::advance}} @@ -3318,9 +3309,6 @@ \effects Value-initializes \tcode{current}. -Iterator operations applied to the resulting iterator have defined behavior -if and only if the corresponding operations are defined on a value-initialized iterator of type -\tcode{Iterator}. \end{itemdescr} \indexlibraryctor{reverse_iterator}% @@ -3436,7 +3424,7 @@ \begin{itemdescr} \pnum \returns -\tcode{current[-n-1]}. +\tcode{current[-n - 1]}. \end{itemdescr} \rSec3[reverse.iter.nav]{Navigation} @@ -3449,7 +3437,7 @@ \begin{itemdescr} \pnum \returns -\tcode{reverse_iterator(current-n)}. +\tcode{reverse_iterator(current - n)}. \end{itemdescr} \indexlibrarymember{operator-}{reverse_iterator}% @@ -3460,7 +3448,7 @@ \begin{itemdescr} \pnum \returns -\tcode{reverse_iterator(current+n)}. +\tcode{reverse_iterator(current + n)}. \end{itemdescr} \indexlibrarymember{operator++}{reverse_iterator}% @@ -3837,6 +3825,8 @@ \rSec3[back.insert.iterator]{Class template \tcode{back_insert_iterator}} +\rSec4[back.insert.iter.general]{General} + \indexlibraryglobal{back_insert_iterator}% \begin{codeblock} namespace std { @@ -3948,6 +3938,8 @@ \rSec3[front.insert.iterator]{Class template \tcode{front_insert_iterator}} +\rSec4[front.insert.iter.general]{General} + \indexlibraryglobal{front_insert_iterator}% \begin{codeblock} namespace std { @@ -4059,6 +4051,8 @@ \rSec3[insert.iterator]{Class template \tcode{insert_iterator}} +\rSec4[insert.iter.general]{General} + \indexlibraryglobal{insert_iterator}% \begin{codeblock} namespace std { @@ -4259,7 +4253,7 @@ template<@\libconcept{convertible_to}@ U> constexpr basic_const_iterator(basic_const_iterator current); template<@\exposconcept{different-from}@ T> - requires @\libconcept{convertible_to}@ + requires @\libconcept{convertible_to}@ constexpr basic_const_iterator(T&& current); constexpr const Iterator& base() const & noexcept; @@ -4267,8 +4261,8 @@ constexpr @\exposid{reference}@ operator*() const; constexpr const auto* operator->() const - requires is_lvalue_reference_v> && - @\libconcept{same_as}@>, value_type>; + requires is_lvalue_reference_v> && + @\libconcept{same_as}@>, value_type>; constexpr basic_const_iterator& operator++(); constexpr void operator++(int); @@ -4288,6 +4282,13 @@ template<@\libconcept{sentinel_for}@ S> constexpr bool operator==(const S& s) const; + template<@\exposconcept{not-a-const-iterator}@ CI> + requires @\exposconcept{constant-iterator}@ && @\libconcept{convertible_to}@ + constexpr operator CI() const &; + template<@\exposconcept{not-a-const-iterator}@ CI> + requires @\exposconcept{constant-iterator}@ && @\libconcept{convertible_to}@ + constexpr operator CI() &&; + constexpr bool operator<(const basic_const_iterator& y) const requires @\libconcept{random_access_iterator}@; constexpr bool operator>(const basic_const_iterator& y) const @@ -4590,6 +4591,30 @@ Equivalent to: \tcode{return \exposid{current_} == s;} \end{itemdescr} +\begin{itemdecl} +template<@\exposconcept{not-a-const-iterator}@ CI> + requires @\exposconcept{constant-iterator}@ && @\libconcept{convertible_to}@ +constexpr operator CI() const &; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{current_}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{not-a-const-iterator}@ CI> + requires @\exposconcept{constant-iterator}@ && @\libconcept{convertible_to}@ +constexpr operator CI() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{std::move(\exposid{current_})}. +\end{itemdescr} + \indexlibrarymember{operator<}{basic_const_iterator}% \indexlibrarymember{operator>}{basic_const_iterator}% \indexlibrarymember{operator<=}{basic_const_iterator}% @@ -5265,7 +5290,7 @@ \indexlibraryglobal{make_move_iterator}% \begin{itemdecl} template -constexpr move_iterator make_move_iterator(Iterator i); + constexpr move_iterator make_move_iterator(Iterator i); \end{itemdecl} \begin{itemdescr} @@ -5458,7 +5483,7 @@ friend constexpr iter_difference_t operator-( const common_iterator& x, const common_iterator& y); - friend constexpr iter_rvalue_reference_t iter_move(const common_iterator& i) + friend constexpr decltype(auto) iter_move(const common_iterator& i) noexcept(noexcept(ranges::iter_move(declval()))) requires @\libconcept{input_iterator}@; template<@\libconcept{indirectly_swappable}@ I2, class S2> @@ -5477,7 +5502,7 @@ template<@\libconcept{input_iterator}@ I, class S> struct iterator_traits> { using iterator_concept = @\seebelow@; - using iterator_category = @\seebelow@; + using iterator_category = @\seebelow@; // not always present using value_type = iter_value_t; using difference_type = iter_difference_t; using pointer = @\seebelow@; @@ -5489,22 +5514,25 @@ \rSec3[common.iter.types]{Associated types} \pnum -The nested \grammarterm{typedef-name}s of the specialization of -\tcode{iterator_traits} for \tcode{common_iterator} are defined as follows. +The nested \grammarterm{typedef-name} \tcode{iterator_category} of +the specialization of \tcode{iterator_traits} for \tcode{common_iterator} +is defined if and only if \tcode{iter_difference_t} is an integral type. +In that case, +\tcode{iterator_category} denotes \tcode{forward_iterator_tag} if +the \grammarterm{qualified-id} \tcode{iterator_traits::iterator_category} +is valid and denotes a type that +models \tcode{\libconcept{derived_from}}; +otherwise it denotes \tcode{input_iterator_tag}. + +\pnum +The remaining nested \grammarterm{typedef-name}s of the specialization of +\tcode{iterator_traits} for \tcode{common_iterator} are defined as follows: \begin{itemize} \item \tcode{iterator_concept} denotes \tcode{forward_iterator_tag} if \tcode{I} models \libconcept{forward_iterator}; otherwise it denotes \tcode{input_iterator_tag}. -\item -\tcode{iterator_category} denotes -\tcode{forward_iterator_tag} -if the \grammarterm{qualified-id} \tcode{iterator_traits::iter\-ator_category} -is valid and denotes a type that -models \tcode{\libconcept{derived_from}}; -otherwise it denotes \tcode{input_iterator_tag}. - \item Let \tcode{a} denote an lvalue of type \tcode{const common_iterator}. If the expression \tcode{a.operator->()} is well-formed, @@ -5797,7 +5825,7 @@ \indexlibrarymember{iter_move}{common_iterator}% \begin{itemdecl} -friend constexpr iter_rvalue_reference_t iter_move(const common_iterator& i) +friend constexpr decltype(auto) iter_move(const common_iterator& i) noexcept(noexcept(ranges::iter_move(declval()))) requires @\libconcept{input_iterator}@; \end{itemdecl} @@ -5956,7 +5984,7 @@ 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) + friend constexpr decltype(auto) iter_move(const counted_iterator& i) noexcept(noexcept(ranges::iter_move(i.current))) requires @\libconcept{input_iterator}@; template<@\libconcept{indirectly_swappable}@ I2> @@ -6384,7 +6412,7 @@ \indexlibrarymember{iter_move}{counted_iterator}% \begin{itemdecl} -friend constexpr iter_rvalue_reference_t +friend constexpr decltype(auto) iter_move(const counted_iterator& i) noexcept(noexcept(ranges::iter_move(i.current))) requires @\libconcept{input_iterator}@; @@ -7212,7 +7240,10 @@ headers are included: \libheaderref{array}, \libheaderref{deque}, +\libheaderrefx{flat_map}{flat.map.syn}, +\libheaderrefx{flat_set}{flat.set.syn}, \libheaderrefx{forward_list}{forward.list.syn}, +\libheaderrefx{inplace_vector}{inplace.vector.syn}, \libheaderref{list}, \libheaderrefx{map}{associative.map.syn}, \libheaderrefx{regex}{re.syn}, @@ -7420,7 +7451,7 @@ \indexlibrary{\idxcode{empty(C\& c)}}% \begin{itemdecl} -template [[nodiscard]] constexpr auto empty(const C& c) -> decltype(c.empty()); +template constexpr auto empty(const C& c) -> decltype(c.empty()); \end{itemdecl} \begin{itemdescr} \pnum @@ -7430,7 +7461,7 @@ \indexlibrary{\idxcode{empty(T (\&array)[N])}}% \begin{itemdecl} -template [[nodiscard]] constexpr bool empty(const T (&array)[N]) noexcept; +template constexpr bool empty(const T (&array)[N]) noexcept; \end{itemdecl} \begin{itemdescr} \pnum @@ -7440,7 +7471,7 @@ \indexlibrary{\idxcode{empty(initializer_list)}}% \begin{itemdecl} -template [[nodiscard]] constexpr bool empty(initializer_list il) noexcept; +template constexpr bool empty(initializer_list il) noexcept; \end{itemdecl} \begin{itemdescr} \pnum diff --git a/source/layout.tex b/source/layout.tex index b74849dd00..1f82bd20d9 100644 --- a/source/layout.tex +++ b/source/layout.tex @@ -10,7 +10,7 @@ %%-------------------------------------------------- %% set header and footer positions and sizes -\setheadfoot{\onelineskip}{2\onelineskip} +\setheadfoot{\onelineskip}{4\onelineskip} \setheaderspaces{*}{2\onelineskip}{*} %%-------------------------------------------------- diff --git a/source/lex.tex b/source/lex.tex index b4b81cf407..6cf011e432 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -32,7 +32,10 @@ A source file together with all the headers\iref{headers} and source files included\iref{cpp.include} via the preprocessing directive \tcode{\#include}, less any source lines skipped by any of the -conditional inclusion\iref{cpp.cond} preprocessing directives, is +conditional inclusion\iref{cpp.cond} preprocessing directives, +as modified by the implementation-defined behavior of any +conditionally-supported-directives\iref{cpp.pre} and pragmas\iref{cpp.pragma}, +if any, is called a \defnadj{preprocessing}{translation unit}. \begin{note} A \Cpp{} program need not all be translated at the same time. @@ -80,8 +83,14 @@ \end{note} If an input file is determined to be a UTF-8 file, then it shall be a well-formed UTF-8 code unit sequence and -it is decoded to produce a sequence of Unicode scalar values. -A sequence of translation character set elements is then formed +it is decoded to produce a sequence of Unicode +\begin{footnote} +Unicode\textregistered\ is a registered trademark of Unicode, Inc. +This information is given for the convenience of users of this document and +does not constitute an endorsement by ISO or IEC of this product. +\end{footnote} +scalar values. +A sequence of translation character set elements\iref{lex.charset} is then formed by mapping each Unicode scalar value to the corresponding translation character set element. In the resulting sequence, @@ -93,8 +102,8 @@ For any other kind of input file supported by the implementation, characters are mapped, in an -\impldef{mapping physical source file characters to translation character set} manner, -to a sequence of translation character set elements\iref{lex.charset}, +\impldef{mapping input file characters to translation character set} manner, +to a sequence of translation character set elements, representing end-of-line indicators as new-line characters. \item @@ -105,15 +114,15 @@ immediately followed by zero or more whitespace characters other than new-line followed by a new-line character is deleted, splicing -physical source lines to form logical source lines. Only the last +physical source lines to form \defnx{logical source lines}{source line!logical}. Only the last backslash on any physical source line shall be eligible for being part of such a splice. \begin{note} Line splicing can form a \grammarterm{universal-character-name}\iref{lex.charset}. \end{note} -A source file that is not empty and that does not end in a new-line -character, or that ends in a splice, +A source file that is not empty and that (after splicing) +does not end in a new-line character shall be processed as if an additional new-line character were appended to the file. @@ -131,7 +140,7 @@ would arise from a source file ending with an unclosed \tcode{/*} comment. \end{footnote} -Each comment is replaced by one space character. New-line characters are +Each comment\iref{lex.comment} is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of whitespace characters other than new-line is retained or replaced by one space character is unspecified. @@ -144,37 +153,40 @@ \grammarterm{r-char-sequence}, \grammarterm{h-char-sequence}, or \grammarterm{q-char-sequence}, -\grammarterm{universal-character-name}s are recognized and -replaced by the designated element of the translation character set. +\grammarterm{universal-character-name}s are recognized\iref{lex.universal.char} and +replaced by the designated element of the translation character set\iref{lex.charset}. The process of dividing a source file's characters into preprocessing tokens is context-dependent. \begin{example} See the handling of \tcode{<} within a \tcode{\#include} preprocessing -directive\iref{cpp.include}. +directive\iref{lex.header,cpp.include}. \end{example} -\item Preprocessing directives are executed, macro invocations are -expanded, and \tcode{_Pragma} unary operator expressions are executed. -A \tcode{\#include} preprocessing directive causes the named header or +\item The source file is analyzed as a \grammarterm{preprocessing-file}\iref{cpp.pre}. +Preprocessing directives\iref{cpp} are executed, macro invocations are +expanded\iref{cpp.replace}, and \tcode{_Pragma} unary operator expressions are executed\iref{cpp.pragma.op}. +A \tcode{\#include} preprocessing directive\iref{cpp.include} causes the named header or source file to be processed from phase 1 through phase 4, recursively. All preprocessing directives are then deleted. \item -For a sequence of two or more adjacent \grammarterm{string-literal} tokens, +For a sequence of two or more adjacent \grammarterm{string-literal} preprocessing tokens, a common \grammarterm{encoding-prefix} is determined as specified in \ref{lex.string}. -Each such \grammarterm{string-literal} token is then considered to have +Each such \grammarterm{string-literal} preprocessing token is then considered to have that common \grammarterm{encoding-prefix}. \item -Adjacent \grammarterm{string-literal} tokens are concatenated\iref{lex.string}. +\indextext{concatenation!string}% +Adjacent \grammarterm{string-literal} preprocessing tokens are concatenated\iref{lex.string}. -\item Whitespace characters separating tokens are no longer -significant. Each preprocessing token is converted into a -token\iref{lex.token}. The resulting tokens -constitute a \defn{translation unit} and +\item +Each preprocessing token is converted into a token\iref{lex.token}. +Whitespace characters separating tokens are no longer significant. +The resulting tokens constitute a \defn{translation unit} and are syntactically and -semantically analyzed and translated. +semantically analyzed as a \grammarterm{translation-unit}\iref{basic.link} and +translated. \begin{note} The process of analyzing and translating the tokens can occasionally result in one token being replaced by a sequence of other @@ -232,7 +244,9 @@ The program is ill-formed if any instantiation fails. -\item All external entity references are resolved. Library +\item +\indextext{linking}% +All external entity references are resolved. Library components are linked to satisfy external references to entities not defined in the current translation. All such translator output is collected into a program image which contains information @@ -240,7 +254,9 @@ \indextext{translation!phases|)} \end{enumerate} -\rSec1[lex.charset]{Character sets} +\rSec1[lex.char]{Characters}% + +\rSec2[lex.charset]{Character sets} \pnum \indextext{character set|(}% @@ -317,18 +333,75 @@ \end{floattable} \pnum -The \grammarterm{universal-character-name} construct provides a way to name -other characters. +The \defnadj{basic literal}{character set} consists of +all characters of the basic character set, +plus the control characters specified in \tref{lex.charset.literal}. + +\begin{floattable}{Additional control characters in the basic literal character set}{lex.charset.literal}{ll} +\topline +\ohdrx{2}{character} \\ \capsep +\ucode{0000} & \uname{null} \\ +\ucode{0007} & \uname{alert} \\ +\ucode{0008} & \uname{backspace} \\ +\ucode{000d} & \uname{carriage return} \\ +\end{floattable} + +\pnum +A \defn{code unit} is an integer value +of character type\iref{basic.fundamental}. +Characters in a \grammarterm{character-literal} +other than a multicharacter or non-encodable character literal or +in a \grammarterm{string-literal} are encoded as +a sequence of one or more code units, as determined +by the \grammarterm{encoding-prefix}\iref{lex.ccon,lex.string}; +this is termed the respective \defnadj{literal}{encoding}. +The \defnadj{ordinary literal}{encoding} is +the encoding applied to an ordinary character or string literal. +The \defnadj{wide literal}{encoding} is the encoding applied +to a wide character or string literal. + +\pnum +A literal encoding or a locale-specific encoding of one of +the execution character sets\iref{character.seq} +encodes each element of the basic literal character set as +a single code unit with non-negative value, +distinct from the code unit for any other such element. +\begin{note} +A character not in the basic literal character set +can be encoded with more than one code unit; +the value of such a code unit can be the same as +that of a code unit for an element of the basic literal character set. +\end{note} +\indextext{character!null}% +\indextext{wide-character!null}% +The \unicode{0000}{null} character is encoded as the value \tcode{0}. +No other element of the translation character set +is encoded with a code unit of value \tcode{0}. +The code unit value of each decimal digit character after the digit \tcode{0} (\ucode{0030}) +shall be one greater than the value of the previous. +The ordinary and wide literal encodings are otherwise +\impldef{ordinary and wide literal encodings}. +\indextext{UTF-8}% +\indextext{UTF-16}% +\indextext{UTF-32}% +For a UTF-8, UTF-16, or UTF-32 literal, +the implementation shall encode +the Unicode scalar value +corresponding to each character of the translation character set +as specified in the Unicode Standard +for the respective Unicode encoding form. +\indextext{character set|)} + +\rSec2[lex.universal.char]{Universal character names} \begin{bnf} -\nontermdef{n-char} \textnormal{one of}\br +\nontermdef{n-char}\br \textnormal{any member of the translation character set except the \unicode{007d}{right curly bracket} or new-line character} \end{bnf} \begin{bnf} \nontermdef{n-char-sequence}\br - n-char\br - n-char-sequence n-char + n-char \opt{n-char-sequence} \end{bnf} \begin{bnf} @@ -343,8 +416,7 @@ \begin{bnf} \nontermdef{simple-hexadecimal-digit-sequence}\br - hexadecimal-digit\br - simple-hexadecimal-digit-sequence hexadecimal-digit + hexadecimal-digit \opt{simple-hexadecimal-digit-sequence} \end{bnf} \begin{bnf} @@ -355,6 +427,22 @@ named-universal-character \end{bnf} +\pnum +The \grammarterm{universal-character-name} construct provides a way to name any +element in the translation character set using just the basic character set. +If a \grammarterm{universal-character-name} outside +the \grammarterm{c-char-sequence}, \grammarterm{s-char-sequence}, or +\grammarterm{r-char-sequence} of a \grammarterm{character-literal} or +\grammarterm{string-literal} +(in either case, including within a \grammarterm{user-defined-literal}) +corresponds to a control character or to a character in the basic character set, +the program is ill-formed. +\begin{note} +A sequence of characters resembling a \grammarterm{universal-character-name} in an +\grammarterm{r-char-sequence}\iref{lex.string} does not form a +\grammarterm{universal-character-name}. +\end{note} + \pnum A \grammarterm{universal-character-name} of the form \tcode{\textbackslash u} \grammarterm{hex-quad}, @@ -382,79 +470,28 @@ None of these names or aliases have leading or trailing spaces. \end{note} -\pnum -If a \grammarterm{universal-character-name} outside -the \grammarterm{c-char-sequence}, \grammarterm{s-char-sequence}, or -\grammarterm{r-char-sequence} of -a \grammarterm{character-literal} or \grammarterm{string-literal} -(in either case, including within a \grammarterm{user-defined-literal}) -corresponds to a control character or -to a character in the basic character set, the program is ill-formed. -\begin{note} -A sequence of characters resembling a \grammarterm{universal-character-name} in an -\grammarterm{r-char-sequence}\iref{lex.string} does not form a -\grammarterm{universal-character-name}. -\end{note} - -\pnum -The \defnadj{basic literal}{character set} consists of -all characters of the basic character set, -plus the control characters specified in \tref{lex.charset.literal}. - -\begin{floattable}{Additional control characters in the basic literal character set}{lex.charset.literal}{ll} -\topline -\ohdrx{2}{character} \\ \capsep -\ucode{0000} & \uname{null} \\ -\ucode{0007} & \uname{alert} \\ -\ucode{0008} & \uname{backspace} \\ -\ucode{000d} & \uname{carriage return} \\ -\end{floattable} - -\pnum -A \defn{code unit} is an integer value -of character type\iref{basic.fundamental}. -Characters in a \grammarterm{character-literal} -other than a multicharacter or non-encodable character literal or -in a \grammarterm{string-literal} are encoded as -a sequence of one or more code units, as determined -by the \grammarterm{encoding-prefix}\iref{lex.ccon,lex.string}; -this is termed the respective \defnadj{literal}{encoding}. -The \defnadj{ordinary literal}{encoding} is -the encoding applied to an ordinary character or string literal. -The \defnadj{wide literal}{encoding} is the encoding applied -to a wide character or string literal. +\rSec1[lex.comment]{Comments} \pnum -A literal encoding or a locale-specific encoding of one of -the execution character sets\iref{character.seq} -encodes each element of the basic literal character set as -a single code unit with non-negative value, -distinct from the code unit for any other such element. +\indextext{comment|(}% +\indextext{comment!\tcode{/*} \tcode{*/}}% +\indextext{comment!\tcode{//}}% +The characters \tcode{/*} start a comment, which terminates with the +characters \tcode{*/}. These comments do not nest. +\indextext{comment!\tcode{//}}% +The characters \tcode{//} start a comment, which terminates immediately before the +next new-line character. If there is a form-feed or a vertical-tab +character in such a comment, only whitespace characters shall appear +between it and the new-line that terminates the comment; no diagnostic +is required. \begin{note} -A character not in the basic literal character set -can be encoded with more than one code unit; -the value of such a code unit can be the same as -that of a code unit for an element of the basic literal character set. +The comment characters \tcode{//}, \tcode{/*}, +and \tcode{*/} have no special meaning within a \tcode{//} comment and +are treated just like other characters. Similarly, the comment +characters \tcode{//} and \tcode{/*} have no special meaning within a +\tcode{/*} comment. \end{note} -\indextext{character!null}% -\indextext{wide-character!null}% -The \unicode{0000}{null} character is encoded as the value \tcode{0}. -No other element of the translation character set -is encoded with a code unit of value \tcode{0}. -The code unit value of each decimal digit character after the digit \tcode{0} (\ucode{0030}) -shall be one greater than the value of the previous. -The ordinary and wide literal encodings are otherwise -\impldef{ordinary and wide literal encodings}. -\indextext{UTF-8}% -\indextext{UTF-16}% -\indextext{UTF-32}% -For a UTF-8, UTF-16, or UTF-32 literal, -the implementation shall encode -the Unicode scalar value -corresponding to each character of the translation character set -as specified in the Unicode Standard -for the respective Unicode encoding form. -\indextext{character set|)} +\indextext{comment|)} \rSec1[lex.pptoken]{Preprocessing tokens} @@ -475,11 +512,6 @@ \textnormal{each non-whitespace character that cannot be one of the above} \end{bnf} -\pnum -Each preprocessing token that is converted to a token\iref{lex.token} -shall have the lexical form of a keyword, an identifier, a literal, -or an operator or punctuator. - \pnum A preprocessing token is the minimal lexical element of the language in translation phases 3 through 6. @@ -514,6 +546,22 @@ between the quotation characters in a character literal or string literal. +\pnum +Each preprocessing token that is converted to a token\iref{lex.token} +shall have the lexical form of a keyword, an identifier, a literal, +or an operator or punctuator. + +\pnum +The \grammarterm{import-keyword} is produced +by processing an \keyword{import} directive\iref{cpp.import}, +the \grammarterm{module-keyword} is produced +by preprocessing a \keyword{module} directive\iref{cpp.module}, and +the \grammarterm{export-keyword} is produced +by preprocessing either of the previous two directives. +\begin{note} +None has any observable spelling. +\end{note} + \pnum If the input stream has been parsed into preprocessing tokens up to a given character: @@ -543,7 +591,7 @@ except that a \grammarterm{header-name}\iref{lex.header} is only formed \begin{itemize} \item -after the \tcode{include} or \tcode{import} preprocessing token in an +after the \tcode{include} or \tcode{import} preprocessing token in a \tcode{\#include}\iref{cpp.include} or \tcode{import}\iref{cpp.import} directive, or @@ -553,6 +601,7 @@ \end{itemize} \end{itemize} +\pnum \begin{example} \begin{codeblock} #define R "x" @@ -560,17 +609,6 @@ \end{codeblock} \end{example} -\pnum -The \grammarterm{import-keyword} is produced -by processing an \keyword{import} directive\iref{cpp.import}, -the \grammarterm{module-keyword} is produced -by preprocessing a \keyword{module} directive\iref{cpp.module}, and -the \grammarterm{export-keyword} is produced -by preprocessing either of the previous two directives. -\begin{note} -None has any observable spelling. -\end{note} - \pnum \begin{example} The program fragment \tcode{0xe+foo} is parsed as a @@ -593,112 +631,11 @@ \end{example} \indextext{token!preprocessing|)} -\rSec1[lex.digraph]{Alternative tokens} - -\pnum -\indextext{token!alternative|(}% -Alternative token representations are provided for some operators and -punctuators. -\begin{footnote} -\indextext{digraph}% -These include ``digraphs'' and additional reserved words. The term -``digraph'' (token consisting of two characters) is not perfectly -descriptive, since one of the alternative \grammarterm{preprocessing-token}s is -\tcode{\%:\%:} and of course several primary tokens contain two -characters. Nonetheless, those alternative tokens that aren't lexical -keywords are colloquially known as ``digraphs''. -\end{footnote} - -\pnum -In all respects of the language, each alternative token behaves the -same, respectively, as its primary token, except for its spelling. -\begin{footnote} -Thus the ``stringized'' values\iref{cpp.stringize} of -\tcode{[} and \tcode{<:} will be different, maintaining the source -spelling, but the tokens can otherwise be freely interchanged. -\end{footnote} -The set of alternative tokens is defined in -\tref{lex.digraph}. - -\begin{tokentable}{Alternative tokens}{lex.digraph}{Alternative}{Primary} -\tcode{<\%} & \tcode{\{} & -\keyword{and} & \tcode{\&\&} & -\keyword{and_eq} & \tcode{\&=} \\ \rowsep -\tcode{\%>} & \tcode{\}} & -\keyword{bitor} & \tcode{|} & -\keyword{or_eq} & \tcode{|=} \\ \rowsep -\tcode{<:} & \tcode{[} & -\keyword{or} & \tcode{||} & -\keyword{xor_eq} & \tcode{\caret=} \\ \rowsep -\tcode{:>} & \tcode{]} & -\keyword{xor} & \tcode{\caret} & -\keyword{not} & \tcode{!} \\ \rowsep -\tcode{\%:} & \tcode{\#} & -\keyword{compl} & \tcode{\~} & -\keyword{not_eq} & \tcode{!=} \\ \rowsep -\tcode{\%:\%:} & \tcode{\#\#} & -\keyword{bitand} & \tcode{\&} & - & \\ -\end{tokentable}% -\indextext{token!alternative|)} - -\rSec1[lex.token]{Tokens} - -\indextext{token|(}% -\begin{bnf} -\nontermdef{token}\br - identifier\br - keyword\br - literal\br - operator-or-punctuator -\end{bnf} - -\pnum -\indextext{\idxgram{token}}% -There are five kinds of tokens: identifiers, keywords, literals,% -\begin{footnote} -Literals include strings and character and numeric literals. -\end{footnote} -operators, and other separators. -\indextext{whitespace}% -Blanks, horizontal and vertical tabs, newlines, formfeeds, and comments -(collectively, ``whitespace''), as described below, are ignored except -as they serve to separate tokens. -\begin{note} -Some whitespace is -required to separate otherwise adjacent identifiers, keywords, numeric -literals, and alternative tokens containing alphabetic characters. -\end{note} -\indextext{token|)} - -\rSec1[lex.comment]{Comments} - -\pnum -\indextext{comment|(}% -\indextext{comment!\tcode{/*} \tcode{*/}}% -\indextext{comment!\tcode{//}}% -The characters \tcode{/*} start a comment, which terminates with the -characters \tcode{*/}. These comments do not nest. -\indextext{comment!\tcode{//}}% -The characters \tcode{//} start a comment, which terminates immediately before the -next new-line character. If there is a form-feed or a vertical-tab -character in such a comment, only whitespace characters shall appear -between it and the new-line that terminates the comment; no diagnostic -is required. -\begin{note} -The comment characters \tcode{//}, \tcode{/*}, -and \tcode{*/} have no special meaning within a \tcode{//} comment and -are treated just like other characters. Similarly, the comment -characters \tcode{//} and \tcode{/*} have no special meaning within a -\tcode{/*} comment. -\end{note} -\indextext{comment|)} - \rSec1[lex.header]{Header names} \indextext{header!name|(}% \begin{bnf} -\microtypesetup{protrusion=false}\obeyspaces +\microtypesetup{protrusion=false} \nontermdef{header-name}\br \terminal{<} h-char-sequence \terminal{>}\br \terminal{"} q-char-sequence \terminal{"} @@ -706,8 +643,7 @@ \begin{bnf} \nontermdef{h-char-sequence}\br - h-char\br - h-char-sequence h-char + h-char \opt{h-char-sequence} \end{bnf} \begin{bnf} @@ -717,8 +653,7 @@ \begin{bnf} \nontermdef{q-char-sequence}\br - q-char\br - q-char-sequence q-char + q-char \opt{q-char-sequence} \end{bnf} \begin{bnf} @@ -727,16 +662,16 @@ \end{bnf} \pnum +The sequences in both forms of \grammarterm{header-name}{s} are mapped in an +\impldef{mapping header name to header or external source file} manner to headers or to +external source file names as specified in~\ref{cpp.include}. \begin{note} -Header name preprocessing tokens only appear within +Header name preprocessing tokens appear only within a \tcode{\#include} preprocessing directive, a \tcode{__has_include} preprocessing expression, or after certain occurrences of an \tcode{import} token (see~\ref{lex.pptoken}). \end{note} -The sequences in both forms of \grammarterm{header-name}{s} are mapped in an -\impldef{mapping header name to header or external source file} manner to headers or to -external source file names as specified in~\ref{cpp.include}. \pnum The appearance of either of the characters \tcode{'} or \tcode{\textbackslash} or of @@ -746,12 +681,12 @@ \tcode{/*}, or \tcode{//} in a \grammarterm{q-char-sequence} or an \grammarterm{h-char-sequence}} semantics, as is the appearance of the character \tcode{"} in an \grammarterm{h-char-sequence}. -\begin{footnote} +\begin{note} Thus, a sequence of characters that resembles an escape sequence can result in an error, be interpreted as the character corresponding to the escape sequence, or have a completely different meaning, depending on the implementation. -\end{footnote} +\end{note} \indextext{header!name|)} \rSec1[lex.ppnumber]{Preprocessing numbers} @@ -783,7 +718,127 @@ a \grammarterm{floating-point-literal} token.% \indextext{number!preprocessing|)} +\rSec1[lex.operators]{Operators and punctuators} + +\pnum +\indextext{operator|(}% +\indextext{punctuator|(}% +The lexical representation of \Cpp{} programs includes a number of +preprocessing tokens that are used in the syntax of the preprocessor or +are converted into tokens for operators and punctuators: + +\begin{bnf} +\nontermdef{preprocessing-op-or-punc}\br + preprocessing-operator\br + operator-or-punctuator +\end{bnf} + +\begin{bnf} +%% Ed. note: character protrusion would misalign various operators. +\microtypesetup{protrusion=false} +\nontermdef{preprocessing-operator} \textnormal{one of}\br + \terminal{\# \ \ \ \ \ \ \ \#\# \ \ \ \ \ \ \%: \ \ \ \ \ \ \%:\%:} +\end{bnf} + +\begin{bnf} +\microtypesetup{protrusion=false} +\nontermdef{operator-or-punctuator} \textnormal{one of}\br + \terminal{\{ \ \ \ \ \ \ \ \} \ \ \ \ \ \ \ [ \ \ \ \ \ \ \ ] \ \ \ \ \ \ \ ( \ \ \ \ \ \ \ )}\br + \terminal{<\% \ \ \ \ \ \ \%> \ \ \ \ \ \ <: \ \ \ \ \ \ :> \ \ \ \ \ \ ; \ \ \ \ \ \ \ : \ \ \ \ \ \ \ ...}\br + \terminal{? \ \ \ \ \ \ \ :: \ \ \ \ \ \ . \ \ \ \ \ \ \ .* \ \ \ \ \ \ -> \ \ \ \ \ \ ->* \ \ \ \ \ \~}\br + \terminal{! \ \ \ \ \ \ \ + \ \ \ \ \ \ \ - \ \ \ \ \ \ \ * \ \ \ \ \ \ \ / \ \ \ \ \ \ \ \% \ \ \ \ \ \ \ \caret{} \ \ \ \ \ \ \ \& \ \ \ \ \ \ \ |}\br + \terminal{= \ \ \ \ \ \ \ += \ \ \ \ \ \ -= \ \ \ \ \ \ *= \ \ \ \ \ \ /= \ \ \ \ \ \ \%= \ \ \ \ \ \ \caret{}= \ \ \ \ \ \ \&= \ \ \ \ \ \ |=}\br + \terminal{== \ \ \ \ \ \ != \ \ \ \ \ \ < \ \ \ \ \ \ \ > \ \ \ \ \ \ \ <= \ \ \ \ \ \ >= \ \ \ \ \ \ <=> \ \ \ \ \ \&\& \ \ \ \ \ \ ||}\br + \terminal{<< \ \ \ \ \ \ >> \ \ \ \ \ \ <<= \ \ \ \ \ >>= \ \ \ \ \ ++ \ \ \ \ \ \ -- \ \ \ \ \ \ ,}\br + \terminal{\keyword{and} \ \ \ \ \ \keyword{or} \ \ \ \ \ \ \keyword{xor} \ \ \ \ \ \keyword{not} \ \ \ \ \ \keyword{bitand} \ \ \keyword{bitor} \ \ \ \keyword{compl}}\br + \terminal{\keyword{and_eq} \ \ \keyword{or_eq} \ \ \ \keyword{xor_eq} \ \ \keyword{not_eq}} +\end{bnf} + +Each \grammarterm{operator-or-punctuator} is converted to a single token +in translation phase 7\iref{lex.phases}.% +\indextext{punctuator|)}% +\indextext{operator|)} + +\rSec1[lex.digraph]{Alternative tokens} + +\pnum +\indextext{token!alternative|(}% +Alternative token representations are provided for some operators and +punctuators. +\begin{footnote} +\indextext{digraph}% +These include ``digraphs'' and additional reserved words. The term +``digraph'' (token consisting of two characters) is not perfectly +descriptive, since one of the alternative \grammarterm{preprocessing-token}s is +\tcode{\%:\%:} and of course several primary tokens contain two +characters. Nonetheless, those alternative tokens that aren't lexical +keywords are colloquially known as ``digraphs''. +\end{footnote} + +\pnum +In all respects of the language, each alternative token behaves the +same, respectively, as its primary token, except for its spelling. +\begin{footnote} +Thus the ``stringized'' values\iref{cpp.stringize} of +\tcode{[} and \tcode{<:} will be different, maintaining the source +spelling, but the tokens can otherwise be freely interchanged. +\end{footnote} +The set of alternative tokens is defined in +\tref{lex.digraph}. + +\begin{tokentable}{Alternative tokens}{lex.digraph}{Alternative}{Primary} +\tcode{<\%} & \tcode{\{} & +\keyword{and} & \tcode{\&\&} & +\keyword{and_eq} & \tcode{\&=} \\ \rowsep +\tcode{\%>} & \tcode{\}} & +\keyword{bitor} & \tcode{|} & +\keyword{or_eq} & \tcode{|=} \\ \rowsep +\tcode{<:} & \tcode{[} & +\keyword{or} & \tcode{||} & +\keyword{xor_eq} & \tcode{\caret=} \\ \rowsep +\tcode{:>} & \tcode{]} & +\keyword{xor} & \tcode{\caret} & +\keyword{not} & \tcode{!} \\ \rowsep +\tcode{\%:} & \tcode{\#} & +\keyword{compl} & \tcode{\~} & +\keyword{not_eq} & \tcode{!=} \\ \rowsep +\tcode{\%:\%:} & \tcode{\#\#} & +\keyword{bitand} & \tcode{\&} & + & \\ +\end{tokentable}% +\indextext{token!alternative|)} + +\rSec1[lex.token]{Tokens} + +\indextext{token|(}% +\begin{bnf} +\nontermdef{token}\br + identifier\br + keyword\br + literal\br + operator-or-punctuator +\end{bnf} + +\pnum +\indextext{\idxgram{token}}% +There are five kinds of tokens: identifiers, keywords, literals,% +\begin{footnote} +Literals include strings and character and numeric literals. +\end{footnote} +operators, and other separators. +\indextext{whitespace}% +Blanks, horizontal and vertical tabs, newlines, formfeeds, and comments +(collectively, ``whitespace''), as described below, are ignored except +as they serve to separate tokens. +\begin{note} +Whitespace can separate otherwise adjacent identifiers, keywords, numeric +literals, and alternative tokens containing alphabetic characters. +\end{note} +\indextext{token|)} + \rSec1[lex.name]{Identifiers} +\indextext{XID_Start}% +\indextext{XID_Continue}% \indextext{identifier|(}% \begin{bnf} @@ -822,8 +877,7 @@ \indextext{name!length of}% \indextext{name}% \begin{note} -The character properties XID_Start and XID_Continue are Derived Core Properties -as described by \UAX{44} of the Unicode Standard. +The character properties XID_Start and XID_Continue are described by \UAX{44} of the Unicode Standard. \begin{footnote} On systems in which linkers cannot accept extended characters, an encoding of the \grammarterm{universal-character-name} can be used in @@ -858,6 +912,8 @@ \indextext{\idxcode{final}}% \indextext{\idxcode{module}}% \indextext{\idxcode{override}}% +\indextext{\idxcode{replaceable_if_eligible}}% +\indextext{\idxcode{trivially_relocatable_if_eligible}}% The identifiers in \tref{lex.name.special} have a special meaning when appearing in a certain context. When referred to in the grammar, these identifiers are used explicitly rather than using the \grammarterm{identifier} grammar production. @@ -867,13 +923,14 @@ \begin{multicolfloattable}{Identifiers with special meaning}{lex.name.special} {llll} -\keyword{final} \\ -\columnbreak -\keyword{import} \\ -\columnbreak -\keyword{module} \\ -\columnbreak -\keyword{override} \\ +\keyword{final} \\ +\keyword{override} \\\columnbreak +\keyword{import} \\ +\keyword{module} \\\columnbreak +\keyword{post} \\ +\keyword{pre} \\\columnbreak +\keyword{replaceable_if_eligible} \\ +\keyword{trivially_relocatable_if_eligible} \\ \end{multicolfloattable} \pnum @@ -891,7 +948,9 @@ \tcode{\unun} \indextext{character!underscore}% or begins with an underscore followed by -an uppercase letter +an uppercase letter, +other than those specified in this document +(for example, \xname{cplusplus}\iref{cpp.predefined}), \indextext{uppercase}% is reserved to the implementation for any use. \item @@ -945,6 +1004,7 @@ \keyword{constinit} \\ \keyword{const_cast} \\ \keyword{continue} \\ +\keyword{contract_assert} \\ \keyword{co_await} \\ \keyword{co_return} \\ \keyword{co_yield} \\ @@ -958,8 +1018,8 @@ \keyword{enum} \\ \keyword{explicit} \\ \keyword{export} \\ -\keyword{extern} \\ \columnbreak +\keyword{extern} \\ \keyword{false} \\ \keyword{float} \\ \keyword{for} \\ @@ -976,8 +1036,8 @@ \keyword{nullptr} \\ \keyword{operator} \\ \keyword{private} \\ -\keyword{protected} \\ \columnbreak +\keyword{protected} \\ \keyword{public} \\ \keyword{register} \\ \keyword{reinterpret_cast} \\ @@ -994,8 +1054,8 @@ \keyword{template} \\ \keyword{this} \\ \keyword{thread_local} \\ -\keyword{throw} \\ \columnbreak +\keyword{throw} \\ \keyword{true} \\ \keyword{try} \\ \keyword{typedef} \\ @@ -1026,47 +1086,6 @@ \indextext{keyword|)}% -\rSec1[lex.operators]{Operators and punctuators} - -\pnum -\indextext{operator|(}% -\indextext{punctuator|(}% -The lexical representation of \Cpp{} programs includes a number of -preprocessing tokens that are used in the syntax of the preprocessor or -are converted into tokens for operators and punctuators: - -\begin{bnf} -\nontermdef{preprocessing-op-or-punc}\br - preprocessing-operator\br - operator-or-punctuator -\end{bnf} - -\begin{bnf} -%% Ed. note: character protrusion would misalign various operators. -\microtypesetup{protrusion=false}\obeyspaces -\nontermdef{preprocessing-operator} \textnormal{one of}\br - \terminal{\# \#\# \%: \%:\%:} -\end{bnf} - -\begin{bnf} -\microtypesetup{protrusion=false}\obeyspaces -\nontermdef{operator-or-punctuator} \textnormal{one of}\br - \terminal{\{ \} [ ] ( )}\br - \terminal{<: :> <\% \%> ; : ...}\br - \terminal{? :: . .* -> ->* \~}\br - \terminal{! + - * / \% \caret{} \& |}\br - \terminal{= += -= *= /= \%= \caret{}= \&= |=}\br - \terminal{== != < > <= >= <=> \&\& ||}\br - \terminal{<< >> <<= >>= ++ -- ,}\br - \terminal{\keyword{and} \keyword{or} \keyword{xor} \keyword{not} \keyword{bitand} \keyword{bitor} \keyword{compl}}\br - \terminal{\keyword{and_eq} \keyword{or_eq} \keyword{xor_eq} \keyword{not_eq}} -\end{bnf} - -Each \grammarterm{operator-or-punctuator} is converted to a single token -in translation phase 7\iref{lex.phases}.% -\indextext{punctuator|)}% -\indextext{operator|)} - \rSec1[lex.literal]{Literals}% \indextext{literal|(} @@ -1078,8 +1097,7 @@ There are several kinds of literals. \begin{footnote} The term ``literal'' generally designates, in this -document, those tokens that are called ``constants'' in -ISO C. +document, those tokens that are called ``constants'' in C. \end{footnote} \begin{bnf} @@ -1205,7 +1223,7 @@ \grammarterm{octal-digit}s, \grammarterm{digit}s, or \grammarterm{hexadecimal-digit}s -is interpreted as a base $N$ integer as shown in table \tref{lex.icon.base}; +is interpreted as a base $N$ integer as shown in \tref{lex.icon.base}; the lexically first digit of the sequence of digits is the most significant. \begin{note} The prefix and any optional separating single quotes are ignored @@ -1364,8 +1382,7 @@ \begin{bnf} \nontermdef{c-char-sequence}\br - c-char\br - c-char-sequence c-char + c-char \opt{c-char-sequence} \end{bnf} \begin{bnf} @@ -1406,8 +1423,7 @@ \begin{bnf} \nontermdef{simple-octal-digit-sequence}\br - octal-digit\br - simple-octal-digit-sequence octal-digit + octal-digit \opt{simple-octal-digit-sequence} \end{bnf} \begin{bnf} @@ -1415,7 +1431,7 @@ \terminal{\textbackslash} octal-digit\br \terminal{\textbackslash} octal-digit octal-digit\br \terminal{\textbackslash} octal-digit octal-digit octal-digit\br - \terminal{\textbackslash o\{} simple-octal-digit-sequence \terminal{\}}\br + \terminal{\textbackslash o\{} simple-octal-digit-sequence \terminal{\}} \end{bnf} \begin{bnf} @@ -1464,8 +1480,8 @@ \begin{floattable}{Character literals}{lex.ccon.literal} {l|l|l|l|l} \topline -Encoding & Kind & Type & Associated char- & Example \\ -prefix & & & acter encoding & \\ +\lhdr{Encoding} & \chdr{Kind} & \chdr{Type} & \chdr{Associated char-} & \rhdr{Example} \\ +\lhdr{prefix} & \chdr{} & \chdr{} & \chdr{acter encoding} & \\ \capsep none & \defnx{ordinary character literal}{literal!character!ordinary} & @@ -1566,7 +1582,7 @@ is specified in \tref{lex.ccon.esc}. \begin{note} Using an escape sequence for a question mark -is supported for compatibility with ISO \CppXIV{} and ISO C. +is supported for compatibility with \CppXIV{} and C. \end{note} \begin{floattable}{Simple escape sequences}{lex.ccon.esc} @@ -1672,7 +1688,7 @@ \topline \lhdr{\grammarterm{floating-point-suffix}} & \rhdr{type} \\ \capsep none & \keyword{double} \\ -\tcode{f} or \tcode{F} & \keyword {float} \\ +\tcode{f} or \tcode{F} & \keyword{float} \\ \tcode{l} or \tcode{L} & \keyword{long} \keyword{double} \\ \tcode{f16} or \tcode{F16} & \tcode{std::float16_t} \\ \tcode{f32} or \tcode{F32} & \tcode{std::float32_t} \\ @@ -1735,8 +1751,7 @@ \begin{bnf} \nontermdef{s-char-sequence}\br - s-char\br - s-char-sequence s-char + s-char \opt{s-char-sequence} \end{bnf} \begin{bnf} @@ -1759,8 +1774,7 @@ \begin{bnf} \nontermdef{r-char-sequence}\br - r-char\br - r-char-sequence r-char + r-char \opt{r-char-sequence} \end{bnf} \begin{bnf} @@ -1771,8 +1785,7 @@ \begin{bnf} \nontermdef{d-char-sequence}\br - d-char\br - d-char-sequence d-char + d-char \opt{d-char-sequence} \end{bnf} \begin{bnf} @@ -1798,14 +1811,16 @@ are determined by its encoding prefix and sequence of \grammarterm{s-char}s or \grammarterm{r-char}s as defined by \tref{lex.string.literal} -where $n$ is the number of encoded code units as described below. +where $n$ is the number of encoded code units +that would result from an evaluation of the \grammarterm{string-literal} +(see below). \begin{floattable}{String literals}{lex.string.literal} {llp{2.6cm}p{2.3cm}p{4.7cm}} \topline -Encoding & Kind & Type & Associated & Examples \\ -prefix & & & character & \\ - & & & encoding & \\ +\lhdr{Enco-} & \chdr{Kind} & \chdr{Type} & \chdr{Associated} & \rhdr{Examples} \\ +\lhdr{ding} & \chdr{} & \chdr{} & \chdr{character} & \rhdr{} \\ +\lhdr{prefix} & \chdr{} & \chdr{} & \chdr{encoding} & \rhdr{} \\ \capsep none & \defnx{ordinary string literal}{literal!string!ordinary} & @@ -1851,7 +1866,7 @@ \pnum \begin{note} -The characters \tcode{'('} and \tcode{')'} are permitted in a +The characters \tcode{'('} and \tcode{')'} can appear in a \grammarterm{raw-string}. Thus, \tcode{R"delimiter((a|b))delimiter"} is equivalent to \tcode{"(a|b)"}. \end{note} @@ -1892,16 +1907,11 @@ \pnum \indextext{concatenation!string}% -The common \grammarterm{encoding-prefix} -for a sequence of adjacent \grammarterm{string-literal}s -is determined pairwise as follows: -If two \grammarterm{string-literal}{s} have -the same \grammarterm{encoding-prefix}, -the common \grammarterm{encoding-prefix} is that \grammarterm{encoding-prefix}. -If one \grammarterm{string-literal} has no \grammarterm{encoding-prefix}, -the common \grammarterm{encoding-prefix} is that -of the other \grammarterm{string-literal}. -Any other combinations are ill-formed. +The \grammarterm{string-literal}{s} in +any sequence of adjacent \grammarterm{string-literal}{s} +shall have at most one unique \grammarterm{encoding-prefix} among them. +The common \grammarterm{encoding-prefix} of the sequence is +that \grammarterm{encoding-prefix}, if any. \begin{note} A \grammarterm{string-literal}'s rawness has no effect on the determination of the common \grammarterm{encoding-prefix}. @@ -1955,11 +1965,12 @@ \pnum Evaluating a \grammarterm{string-literal} results in a string literal object with static storage duration\iref{basic.stc}. -\indextext{string!distinct}% -Whether all \grammarterm{string-literal}s are distinct (that is, are stored in -nonoverlapping objects) and whether successive evaluations of a +\begin{note} +String literal objects are potentially non-unique\iref{intro.object}. +Whether successive evaluations of a \grammarterm{string-literal} yield the same or a different object is unspecified. +\end{note} \begin{note} \indextext{literal!string!undefined change to}% The effect of attempting to modify a string literal object is undefined. @@ -2218,7 +2229,7 @@ and let \placeholder{len} be the number of code units in \placeholder{str} (i.e., its length excluding the terminating null character). If \placeholder{S} contains a literal operator template with -a non-type template parameter for which \placeholder{str} is +a constant template parameter for which \placeholder{str} is a well-formed \grammarterm{template-argument}, the literal \placeholder{L} is treated as a call of the form \begin{codeblock} diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 6fe8e8fa0e..61fcbded40 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -32,21 +32,21 @@ \ref{mem} & Memory management library \\ \ref{meta} & Metaprogramming library \\ \ref{utilities} & General utilities library \\ -\ref{strings} & Strings library \\ \ref{containers} & Containers library \\ \ref{iterators} & Iterators library \\ \ref{ranges} & Ranges library \\ \ref{algorithms} & Algorithms library \\ +\ref{strings} & Strings library \\ +\ref{text} & Text processing library \\ \ref{numerics} & Numerics library \\ \ref{time} & Time library \\ -\ref{localization} & Localization library \\ \ref{input.output} & Input/output library \\ -\ref{re} & Regular expressions library \\ \ref{thread} & Concurrency support library \\ +\ref{exec} & Execution control library \\ \end{floattable} \pnum -The operating system interface described in ISO/IEC/IEEE 9945:2009 is +The operating system interface described in \IsoPosix{} is hereinafter called \defn{POSIX}. \pnum @@ -82,8 +82,13 @@ such as tuples and function wrappers. \pnum -The strings library\iref{strings} provides support for manipulating text represented -as sequences of type \tcode{char}, +The containers\iref{containers}, iterators\iref{iterators}, ranges\iref{ranges}, +and algorithms\iref{algorithms} libraries provide a \Cpp{} program with access +to a subset of the most widely used algorithms and data structures. + +\pnum +The strings library\iref{strings} provides support +for manipulating sequences of type \tcode{char}, sequences of type \keyword{char8_t}, sequences of type \keyword{char16_t}, sequences of type \keyword{char32_t}, @@ -91,9 +96,9 @@ and sequences of any other character-like type. \pnum -The containers\iref{containers}, iterators\iref{iterators}, ranges\iref{ranges}, -and algorithms\iref{algorithms} libraries provide a \Cpp{} program with access -to a subset of the most widely used algorithms and data structures. +The text processing library\iref{text} provides support for text processing, +including formatting, internationalization support and +regular expression matching and searching. \pnum The numerics library\iref{numerics} provides @@ -110,10 +115,6 @@ The time library\iref{time} provides generally useful time utilities. -\pnum -The localization library\iref{localization} provides extended internationalization -support for text processing. - \pnum The input/output library\iref{input.output} provides the \tcode{iostream} @@ -121,14 +122,15 @@ They can be used with other elements of the library, particularly strings, locales, and iterators. -\pnum -The regular expressions library\iref{re} provides regular expression matching and searching. - \pnum The concurrency support library\iref{thread} provides components to create and manage threads, including atomic operations, mutual exclusion, and interthread communication. +\pnum +The execution control library\iref{exec} provides components +supporting execution of function objects. + \rSec1[library.c]{The C standard library} \pnum @@ -144,8 +146,8 @@ may be different from the signatures in the C standard library, and additional overloads may be declared in this document, but the behavior and the preconditions -(including any preconditions implied by the use of an -ISO C \tcode{restrict} qualifier) +(including any preconditions implied by the use of +a C \tcode{restrict} qualifier) are the same unless otherwise stated. \pnum @@ -161,7 +163,7 @@ to the extent applicable to the floating-point types\iref{basic.fundamental} that are parameter types of the called function. \begin{note} -Annex F specifies +\IsoC{}, Annex F specifies the conditions under which floating-point exceptions are raised and the behavior when NaNs and/or infinities are passed as arguments. \end{note} @@ -368,9 +370,32 @@ \item \expects -the conditions -that the function assumes to hold whenever it is called; +conditions that the function assumes to hold whenever it is called; violation of any preconditions results in undefined behavior. +\begin{example} +An implementation can express some such conditions +via the use of a contract assertion, +such as a precondition assertion\iref{dcl.contract.func}. +\end{example} + +\item +\hardexpects +conditions that the function assumes to hold whenever it is called. +\begin{itemize} +\item +When invoking the function in a hardened implementation, +prior to any other observable side effects of the function, +one or more contract assertions +whose predicates are as described in the hardened precondition +are evaluated with a checking semantic\iref{basic.contract.eval}. +If any of these assertions is evaluated with a non-terminating semantic +and the contract-violation handler returns, +the program has undefined behavior. +\item +When invoking the function in a non-hardened implementation, +if any hardened precondition is violated, +the program has undefined behavior. +\end{itemize} \item \effects @@ -384,12 +409,17 @@ \ensures the conditions (sometimes termed observable results) established by the function. +\begin{example} +An implementation can express some such conditions +via the use of a contract assertion, +such as a postcondition assertion\iref{dcl.contract.func}. +\end{example} \item \result for a \grammarterm{typename-specifier}, a description of the named type; for an \grammarterm{expression}, -a description of the type of the expression; +a description of the type and value category of the expression; the expression is an lvalue if the type is an lvalue reference type, an xvalue if the type is an rvalue reference type, and a prvalue otherwise. @@ -422,9 +452,18 @@ If \tcode{F}'s semantics specifies any \Fundescx{Constraints} or \Fundescx{Mandates} elements, then those requirements are logically imposed prior to the \term{equivalent-to} semantics. Next, the semantics of the code sequence are determined by the -\Fundescx{Constraints}, \Fundescx{Mandates}, \Fundescx{Preconditions}, \Fundescx{Effects}, -\Fundescx{Synchronization}, \Fundescx{Postconditions}, \Fundescx{Returns}, \Fundescx{Throws}, -\Fundescx{Complexity}, \Fundescx{Remarks}, and \Fundescx{Error conditions} +\Fundescx{Constraints}, +\Fundescx{Mandates}, +\Fundescx{Preconditions}, +\Fundescx{Hardened preconditions}, +\Fundescx{Effects}, +\Fundescx{Synchronization}, +\Fundescx{Postconditions}, +\Fundescx{Returns}, +\Fundescx{Throws}, +\Fundescx{Complexity}, +\Fundescx{Remarks}, and +\Fundescx{Error conditions} specified for the function invocations contained in the code sequence. The value returned from \tcode{F} is specified by \tcode{F}'s \Fundescx{Returns} element, or if \tcode{F} has no \Fundescx{Returns} element, @@ -499,11 +538,11 @@ namespace std { template requires @\libconcept{convertible_to}@> - constexpr decay_t @\placeholdernc{decay-copy}@(T&& v) - noexcept(is_nothrow_convertible_v>) // \expos + constexpr decay_t @\placeholdernc{decay-copy}@(T&& v) // \expos + noexcept(is_nothrow_convertible_v>) { return std::forward(v); } - constexpr auto @\placeholdernc{synth-three-way}@ = + constexpr auto @\placeholdernc{synth-three-way}@ = // \expos [](const T& t, const U& u) requires requires { { t < u } -> @\exposconcept{boolean-testable}@; @@ -520,10 +559,19 @@ }; template - using @\placeholdernc{synth-three-way-result}@ = decltype(@\placeholdernc{synth-three-way}@(declval(), declval())); + using @\placeholdernc{synth-three-way-result}@ = // \expos + decltype(@\placeholdernc{synth-three-way}@(declval(), declval())); } \end{codeblock} +\pnum +An object \tcode{dst} is said to be \defn{decay-copied from} +a subexpression \tcode{src} +if the type of \tcode{dst} is +\begin{codeblock} +decay_t +\end{codeblock} and \tcode{dst} is copy-initialized from \tcode{src}. + \rSec3[type.descriptions]{Type descriptions} \rSec4[type.descriptions.general]{General} @@ -845,9 +893,40 @@ \item \tcode{std::move(as_const(p))(args...)} \end{itemize} +\rSec3[alg.func.obj]{Algorithm function objects} + +\pnum +An \defn{algorithm function object} is +a customization point object\iref{customization.point.object} +that is specified as one or more overloaded function templates. +The name of these function templates designates +the corresponding algorithm function object. + \pnum -Each customization point object type constrains its return type to model a -particular concept. +For an algorithm function object \tcode{o}, +let $S$ be the corresponding set of function templates. +Then for any sequence of arguments $\tcode{args} \dotsc$, +$\tcode{o(args} \dotsc \tcode{)}$ is expression-equivalent to +$\tcode{s(args} \dotsc \tcode{)}$, +where the result of name lookup for \tcode{s} is the overload set $S$. +\begin{note} +Algorithm function objects are not found by +argument-dependent name lookup\iref{basic.lookup.argdep}. +When found by unqualified name lookup\iref{basic.lookup.unqual} +for the \grammarterm{postfix-expression} in a function call\iref{expr.call}, +they inhibit argument-dependent name lookup. +\begin{example} +\begin{codeblock} +void foo() { + using namespace std::ranges; + std::vector vec{1,2,3}; + find(begin(vec), end(vec), 2); // \#1 +} +\end{codeblock} +The function call expression at \#1 invokes \tcode{std::ranges::find}, +not \tcode{std::find}. +\end{example} +\end{note} \rSec3[functions.within.classes]{Functions within classes} @@ -901,29 +980,63 @@ Unless otherwise specified, the requirements on freestanding items for a freestanding implementation are the same as the corresponding requirements for a hosted implementation, -except that not all of the members of the namespaces are required to be present. +except that not all of the members of those items are required to be present. + +\pnum +Function declarations and function template declarations +followed by a comment that include \textit{freestanding-deleted} are +\defnadjx{freestanding deleted}{functions}{function}. +On freestanding implementations, +it is \impldef{whether a freestanding deleted function is a deleted function} +whether each entity introduced by a freestanding deleted function +is a deleted function\iref{dcl.fct.def.delete} or +whether the requirements are the same as +the corresponding requirements for a hosted implementation. \begin{note} -This implies that freestanding item enumerations have the same enumerators on -freestanding implementations and hosted implementations. -Furthermore, class types have the same members and -class templates have the same deduction guides -on freestanding implementations and hosted implementations. +Deleted definitions reduce the chance of overload resolution silently changing +when migrating from a freestanding implementation to a hosted implementation. \end{note} +\begin{example} +\begin{codeblock} +double abs(double j); // freestanding-deleted +\end{codeblock} +\end{example} \pnum \indextext{declaration!freestanding item}% -A declaration in a header synopsis is a freestanding item if +A declaration in a synopsis is a freestanding item if \begin{itemize} -\item it is followed by a comment that includes \textit{freestanding}, or -\item the header synopsis begins with a comment that includes \textit{all freestanding}. +\item it is followed by a comment that includes \textit{freestanding}, +\item it is followed by a comment that includes \textit{freestanding-deleted}, or +\item the header synopsis begins with a comment +that includes \textit{freestanding} and +the declaration is not followed by a comment that includes \textit{hosted}. +\begin{note} +Declarations followed by \textit{hosted} in freestanding headers are +not freestanding items. +As a result, looking up the name of such functions can vary +between hosted and freestanding implementations. +\end{note} \end{itemize} +\begin{example} +\begin{codeblock} +// all freestanding +namespace std { +\end{codeblock} +\end{example} \pnum \indextext{entity!freestanding item}% +\indextext{deduction guide!freestanding item}% \indextext{\idxgram{typedef-name}!freestanding item}% -An entity or \grammarterm{typedef-name} is a freestanding item if it is: +An entity, deduction guide, or \grammarterm{typedef-name} +is a freestanding item if its introducing declaration is not followed by +a comment that includes \textit{hosted}, and is: \begin{itemize} \item introduced by a declaration that is a freestanding item, +\item a member of a freestanding item other than a namespace, +\item an enumerator of a freestanding item, +\item a deduction guide of a freestanding item, \item an enclosing namespace of a freestanding item, \item a friend of a freestanding item, \item denoted by a \grammarterm{typedef-name} that is a freestanding item, or @@ -934,35 +1047,40 @@ \indextext{macro!freestanding item}% A macro is a freestanding item if it is defined in a header synopsis and \begin{itemize} -\item the definition is followed by a comment that includes \textit{freestanding}, or -\item the header synopsis begins with a comment that includes \textit{all freestanding}. +\item the definition is followed by a comment +that includes \textit{freestanding}, or +\item the header synopsis begins with a comment +that includes \textit{freestanding} and +the definition is not followed by a comment that includes \textit{hosted}. \end{itemize} - -\pnum \begin{example} \begin{codeblock} #define NULL @\seebelow@ // freestanding \end{codeblock} \end{example} -\begin{example} -\begin{codeblock} -// all freestanding -namespace std { -\end{codeblock} -\end{example} - \pnum -Function declarations and function template declarations -followed by a comment that include \textit{freestanding-deleted} are -\defnadjx{freestanding deleted}{functions}{function}. -On freestanding implementations, -it is \impldef{whether a freestanding deleted function is a freestanding item or a deleted function} -whether each function definition introduced by a freestanding deleted function -is a freestanding item or a deleted function\iref{dcl.fct.def.delete}. +\begin{note} +Freestanding annotations follow some additional exposition conventions +that do not impose any additional normative requirements. +Header synopses that begin with a comment containing "all freestanding" +contain no hosted items and no freestanding deleted functions. +Header synopses that begin with a comment containing "mostly freestanding" +contain at least one hosted item or freestanding deleted function. +Classes and class templates followed by a comment +containing "partially freestanding" +contain at least one hosted item or freestanding deleted function. +\end{note} \begin{example} \begin{codeblock} -double abs(double j); // freestanding-deleted +template struct array; // partially freestanding +template +struct array { + constexpr reference operator[](size_type n); + constexpr const_reference operator[](size_type n) const; + constexpr reference at(size_type n); // freestanding-deleted + constexpr const_reference at(size_type n) const; // freestanding-deleted +}; \end{codeblock} \end{example} @@ -1031,7 +1149,8 @@ \pnum Whenever an unqualified name other than -\tcode{swap}, \tcode{make_error_code}, \tcode{make_error_condition}, or +\tcode{swap}, \tcode{make_error_code}, \tcode{make_error_condition}, +\tcode{from_stream}, or \tcode{submdspan_mapping} is used in the specification of a declaration \tcode{D} in \ref{\firstlibchapter} through \ref{\lastlibchapter} or \ref{depr}, @@ -1055,7 +1174,8 @@ in an overload resolution context for swappable values\iref{swappable.requirements}. The meanings of the unqualified names -\tcode{make_error_code}, \tcode{make_error_condition}, and +\tcode{make_error_code}, \tcode{make_error_condition}, +\tcode{from_stream}, and \tcode{submdspan_mapping} are established as-if by performing argument-dependent lookup\iref{basic.lookup.argdep}. @@ -1088,12 +1208,13 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1102,14 +1223,16 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\columnbreak \tcode{} \\ +\columnbreak \tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1118,6 +1241,7 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1142,6 +1266,7 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1155,7 +1280,6 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1274,7 +1398,7 @@ \end{footnote} \pnum -\ref{support.c.headers}, C standard library headers, describes the effects of using +Subclause \ref{support.c.headers} describes the effects of using the \tcode{\placeholder{name}.h} (C header) form in a \Cpp{} program. \begin{footnote} The @@ -1405,18 +1529,25 @@ \pnum The named module \tcode{std.compat} exports the same declarations as the named module \tcode{std}, and -additionally exports declarations in the global namespace +additionally exports +\begin{itemize} +\item +declarations in the global namespace corresponding to the declarations in namespace \tcode{std} that are provided by the \Cpp{} headers for C library facilities~(\tref{headers.cpp.c}), except the explicitly excluded declarations -described in \ref{support.c.headers.other}. +described in \ref{support.c.headers.other} and +\item +declarations provided by +the headers \libheaderref{stdbit.h} and \libheaderref{stdckdint.h}. +\end{itemize} \pnum It is unspecified to which module a declaration in the standard library is attached. \begin{note} -Implementations are required to ensure that mixing +Conforming implementations ensure that mixing \tcode{\#include} and \tcode{import} does not result in conflicting attachments\iref{basic.link}. \end{note} @@ -1468,30 +1599,43 @@ \ref{support.limits} & Implementation properties & \tcode{}, \tcode{}, \tcode{}, \\ & & \tcode{} \\ \rowsep -\ref{cstdint.syn} & Integer types & \tcode{} \\ \rowsep +\ref{cstdint.syn} & Integer types & \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{cmp} & Comparisons & \tcode{} \\ \rowsep +\ref{support.contract} & Contract-violation handling & \tcode{} \\ \rowsep \ref{support.coroutine} & Coroutines support & \tcode{} \\ \rowsep \ref{support.runtime} & Other runtime support & \tcode{} \\ \rowsep \ref{concepts} & Concepts library & \tcode{} \\ \rowsep \ref{errno} & Error numbers & \tcode{} \\ \rowsep \ref{syserr} & System error support & \tcode{} \\ \rowsep +\ref{debugging} & Debugging & \tcode{} \\ \rowsep \ref{memory} & Memory & \tcode{} \\ \rowsep \ref{type.traits} & Type traits & \tcode{} \\ \rowsep \ref{ratio} & Compile-time rational arithmetic & \tcode{} \\ \rowsep \ref{utility} & Utility components & \tcode{} \\ \rowsep \ref{tuple} & Tuples & \tcode{} \\ \rowsep +\ref{optional} & Optional objects & \tcode{} \\ \rowsep +\ref{variant} & Variants & \tcode{} \\ \rowsep +\ref{expected} & Expected objects & \tcode{} \\ \rowsep \ref{function.objects} & Function objects & \tcode{} \\ \rowsep -\ref{charconv} & Primitive numeric conversions & \tcode{} \\ \rowsep \ref{bit} & Bit manipulation & \tcode{} \\ \rowsep -\ref{string.classes} & String classes & \tcode{} \\ \rowsep -\ref{c.strings} & Null-terminated sequence utilities & \tcode{}, \tcode{} \\ \rowsep +\ref{array} & Class template \tcode{array} & \tcode{} \\ \rowsep +\ref{inplace.vector} & Class template \tcode{inplace_vector} & \tcode{} \\ \rowsep +\ref{views.contiguous} & Contiguous access & \tcode{} \\ \rowsep +\ref{views.multidim} & Multidimensional access & \tcode{} \\ \rowsep \ref{iterators} & Iterators library & \tcode{} \\ \rowsep \ref{ranges} & Ranges library & \tcode{} \\ \rowsep +\ref{algorithms} & Algorithms library & \tcode{}, \tcode{} \\ \rowsep +\ref{execpol} & Execution policies & \tcode{} \\ \rowsep +\ref{string.view} & String view classes & \tcode{} \\ \rowsep +\ref{string.classes} & String classes & \tcode{} \\ \rowsep +\ref{c.strings} & Null-terminated sequence utilities & \tcode{}, \tcode{} \\ \rowsep +\ref{charconv} & Primitive numeric conversions & \tcode{} \\ \rowsep +\ref{rand} & Random number generation & \tcode{} \\ \rowsep \ref{c.math} & Mathematical functions for floating-point types & \tcode{} \\ \rowsep \ref{atomics} & Atomics & \tcode{} \\ \rowsep \end{libsumtab} @@ -1774,7 +1918,7 @@ denote an expression of type \tcode{U}. \pnum -An object \tcode{t} is \defn{swappable with} an object \tcode{u} if and only if: +An object \tcode{t} is \defn{swappable with} an object \tcode{u} if and only if \begin{itemize} \item the expressions \tcode{swap(t, u)} and \tcode{swap(u, t)} are valid when evaluated in the context described below, and @@ -1815,12 +1959,12 @@ swappable with any rvalue or lvalue, respectively, of type \tcode{T}. \pnum -A type \tcode{X} meets the \oldconcept{Swappable} requirements +A type \tcode{X} meets the \defnoldconcept{Swappable} requirements if lvalues of type \tcode{X} are swappable. \pnum A type \tcode{X} meeting any of the iterator requirements\iref{iterator.requirements} -meets the \oldconcept{ValueSwappable} requirements if, +meets the \defnoldconcept{ValueSwappable} requirements if, for any dereferenceable object \tcode{x} of type \tcode{X}, \tcode{*x} is swappable. @@ -1876,7 +2020,7 @@ \pnum A \oldconcept{NullablePointer} type is a pointer-like type that supports null values. -A type \tcode{P} meets the \oldconcept{\-Nullable\-Pointer} requirements if: +A type \tcode{P} meets the \oldconcept{\-Nullable\-Pointer} requirements if \begin{itemize} \item \tcode{P} meets the \oldconcept{EqualityComparable}, \oldconcept{DefaultConstructible}, \oldconcept{CopyConstructible}, \oldconcept{\-Copy\-Assign\-able}, @@ -1891,10 +2035,10 @@ \pnum A value-initialized object of type \tcode{P} produces the null value of the type. The null value shall be equivalent only to itself. A default-initialized object -of type \tcode{P} may have an indeterminate value. +of type \tcode{P} may have an indeterminate or erroneous value. \begin{note} -Operations involving -indeterminate values can cause undefined behavior. +Operations involving indeterminate values can cause undefined behavior, and +operations involving erroneous values can cause erroneous behavior\iref{basic.indet}. \end{note} \pnum @@ -1952,7 +2096,7 @@ \rSec3[hash.requirements]{\oldconcept{Hash} requirements} \pnum -A type \tcode{H} meets the \defnoldconcept{Hash} requirements if: +A type \tcode{H} meets the \defnoldconcept{Hash} requirements if \begin{itemize} \item it is a function object type\iref{function.objects}, \item it meets the \oldconcept{CopyConstructible} (\tref{cpp17.copyconstructible}) and @@ -2000,13 +2144,13 @@ difference, the type of the size of objects in this allocation model, as well as the memory allocation and deallocation primitives for it. All of the string types\iref{strings}, -containers\iref{containers} (except \tcode{array}), +containers\iref{containers} (except \tcode{array} and \tcode{inplace_vector}), string buffers and string streams\iref{input.output}, and \tcode{match_results}\iref{re} are parameterized in terms of allocators. \pnum -In subclause \ref{allocator.requirements}, +In \ref{allocator.requirements}, \begin{itemize} \item \tcode{T}, \tcode{U}, \tcode{C} denote @@ -2174,7 +2318,7 @@ \end{itemdescr} \begin{itemdecl} -typename X::template rebind::other +typename X::rebind::other \end{itemdecl} \begin{itemdescr} @@ -2572,7 +2716,7 @@ \end{itemdescr} \begin{itemdecl} -a.construct(c, args) +a.construct(c, args...) \end{itemdecl} \begin{itemdescr} @@ -2802,6 +2946,22 @@ \end{codeblock} \end{example} +\pnum +The following exposition-only concept defines +the minimal requirements on an Allocator type. +\begin{codeblock} +template +concept @\defexposconcept{simple-allocator}@ = + requires(Alloc alloc, size_t n) { + { *alloc.allocate(n) } -> @\libconcept{same_as}@; + { alloc.deallocate(alloc.allocate(n), n) }; + } && + @\libconcept{copy_constructible}@ && + @\libconcept{equality_comparable}@; +\end{codeblock} +A type \tcode{Alloc} models \exposconcept{simple-allocator} +if it meets the requirements of \ref{allocator.requirements.general}. + \rSec4[allocator.requirements.completeness]{Allocator completeness requirements} \pnum @@ -2933,7 +3093,7 @@ or to a namespace within namespace \tcode{posix} unless otherwise specified. The namespace \tcode{posix} is reserved for use by -ISO/IEC/IEEE 9945 and other POSIX standards. +\IsoPosixUndated{} and other POSIX standards. \rSec4[namespace.future]{Namespaces for future standardization} @@ -2973,83 +3133,132 @@ \indextext{brains!names that want to eat your}% \pnum -In namespace \tcode{std}, the following names are reserved for previous standardization: -\begin{itemize} -\item \indexlibraryzombie{auto_ptr} \tcode{auto_ptr}, -\item \indexlibraryzombie{auto_ptr_ref} \tcode{auto_ptr_ref}, -\item \indexlibraryzombie{binary_function} \tcode{binary_function}, -\item \indexlibraryzombie{binary_negate} \tcode{binary_negate}, -\item \indexlibraryzombie{bind1st} \tcode{bind1st}, -\item \indexlibraryzombie{bind2nd} \tcode{bind2nd}, -\item \indexlibraryzombie{binder1st} \tcode{binder1st}, -\item \indexlibraryzombie{binder2nd} \tcode{binder2nd}, -\item \indexlibraryzombie{const_mem_fun1_ref_t} \tcode{const_mem_fun1_ref_t}, -\item \indexlibraryzombie{const_mem_fun1_t} \tcode{const_mem_fun1_t}, -\item \indexlibraryzombie{const_mem_fun_ref_t} \tcode{const_mem_fun_ref_t}, -\item \indexlibraryzombie{const_mem_fun_t} \tcode{const_mem_fun_t}, -\item \indexlibraryzombie{declare_no_pointers} \tcode{declare_no_pointers}, -\item \indexlibraryzombie{declare_reachable} \tcode{declare_reachable}, -\item \indexlibraryzombie{get_pointer_safety} \tcode{get_pointer_safety}, -\item \indexlibraryzombie{get_temporary_buffer} \tcode{get_temporary_buffer}, -\item \indexlibraryzombie{get_unexpected} \tcode{get_unexpected}, -\item \indexlibraryzombie{gets} \tcode{gets}, -\item \indexlibraryzombie{is_literal_type} \tcode{is_literal_type}, -\item \indexlibraryzombie{is_literal_type_v} \tcode{is_literal_type_v}, -\item \indexlibraryzombie{mem_fun1_ref_t} \tcode{mem_fun1_ref_t}, -\item \indexlibraryzombie{mem_fun1_t} \tcode{mem_fun1_t}, -\item \indexlibraryzombie{mem_fun_ref_t} \tcode{mem_fun_ref_t}, -\item \indexlibraryzombie{mem_fun_ref} \tcode{mem_fun_ref}, -\item \indexlibraryzombie{mem_fun_t} \tcode{mem_fun_t}, -\item \indexlibraryzombie{mem_fun} \tcode{mem_fun}, -\item \indexlibraryzombie{not1} \tcode{not1}, -\item \indexlibraryzombie{not2} \tcode{not2}, -\item \indexlibraryzombie{pointer_safety} \tcode{pointer_safety}, -\item \indexlibraryzombie{pointer_to_binary_function} \tcode{pointer_to_binary_function}, -\item \indexlibraryzombie{pointer_to_unary_function} \tcode{pointer_to_unary_function}, -\item \indexlibraryzombie{ptr_fun} \tcode{ptr_fun}, -\item \indexlibraryzombie{random_shuffle} \tcode{random_shuffle}, -\item \indexlibraryzombie{raw_storage_iterator} \tcode{raw_storage_iterator}, -\item \indexlibraryzombie{result_of} \tcode{result_of}, -\item \indexlibraryzombie{result_of_t} \tcode{result_of_t}, -\item \indexlibraryzombie{return_temporary_buffer} \tcode{return_temporary_buffer}, -\item \indexlibraryzombie{set_unexpected} \tcode{set_unexpected}, -\item \indexlibraryzombie{unary_function} \tcode{unary_function}, -\item \indexlibraryzombie{unary_negate} \tcode{unary_negate}, -\item \indexlibraryzombie{uncaught_exception} \tcode{uncaught_exception}, -\item \indexlibraryzombie{undeclare_no_pointers} \tcode{undeclare_no_pointers}, -\item \indexlibraryzombie{undeclare_reachable} \tcode{undeclare_reachable}, -and -\item \indexlibraryzombie{unexpected_handler} \tcode{unexpected_handler}. -\end{itemize} +In namespace \tcode{std}, the names shown in \tref{zombie.names.std} are +reserved for previous standardization: + +\begin{multicolfloattable}{Zombie names in namespace \tcode{std}}{zombie.names.std} +{lll} +\indexlibraryzombie{auto_ptr} \tcode{auto_ptr} \\ +\indexlibraryzombie{auto_ptr_ref} \tcode{auto_ptr_ref} \\ +\indexlibraryzombie{binary_function} \tcode{binary_function} \\ +\indexlibraryzombie{binary_negate} \tcode{binary_negate} \\ +\indexlibraryzombie{bind1st} \tcode{bind1st} \\ +\indexlibraryzombie{bind2nd} \tcode{bind2nd} \\ +\indexlibraryzombie{binder1st} \tcode{binder1st} \\ +\indexlibraryzombie{binder2nd} \tcode{binder2nd} \\ +\indexlibraryzombie{codecvt_mode} \tcode{codecvt_mode} \\ +\indexlibraryzombie{codecvt_utf16} \tcode{codecvt_utf16} \\ +\indexlibraryzombie{codecvt_utf8} \tcode{codecvt_utf8} \\ +\indexlibraryzombie{codecvt_utf8_utf16} \tcode{codecvt_utf8_utf16} \\ +\indexlibraryzombie{const_mem_fun1_ref_t} \tcode{const_mem_fun1_ref_t} \\ +\indexlibraryzombie{const_mem_fun1_t} \tcode{const_mem_fun1_t} \\ +\indexlibraryzombie{const_mem_fun_ref_t} \tcode{const_mem_fun_ref_t} \\ +\indexlibraryzombie{const_mem_fun_t} \tcode{const_mem_fun_t} \\ +\indexlibraryzombie{consume_header} \tcode{consume_header} \\ +\indexlibraryzombie{declare_no_pointers} \tcode{declare_no_pointers} \\ +\indexlibraryzombie{declare_reachable} \tcode{declare_reachable} \\ +\columnbreak +\indexlibraryzombie{generate_header} \tcode{generate_header} \\ +\indexlibraryzombie{get_pointer_safety} \tcode{get_pointer_safety} \\ +\indexlibraryzombie{get_temporary_buffer} \tcode{get_temporary_buffer} \\ +\indexlibraryzombie{get_unexpected} \tcode{get_unexpected} \\ +\indexlibraryzombie{gets} \tcode{gets} \\ +\indexlibraryzombie{is_literal_type} \tcode{is_literal_type} \\ +\indexlibraryzombie{is_literal_type_v} \tcode{is_literal_type_v} \\ +\indexlibraryzombie{istrstream} \tcode{istrstream} \\ +\indexlibraryzombie{little_endian} \tcode{little_endian} \\ +\indexlibraryzombie{mem_fun1_ref_t} \tcode{mem_fun1_ref_t} \\ +\indexlibraryzombie{mem_fun1_t} \tcode{mem_fun1_t} \\ +\indexlibraryzombie{mem_fun_ref_t} \tcode{mem_fun_ref_t} \\ +\indexlibraryzombie{mem_fun_ref} \tcode{mem_fun_ref} \\ +\indexlibraryzombie{mem_fun_t} \tcode{mem_fun_t} \\ +\indexlibraryzombie{mem_fun} \tcode{mem_fun} \\ +\indexlibraryzombie{not1} \tcode{not1} \\ +\indexlibraryzombie{not2} \tcode{not2} \\ +\indexlibraryzombie{ostrstream} \tcode{ostrstream} \\ +\indexlibraryzombie{pointer_safety} \tcode{pointer_safety} \\ +\columnbreak +\indexlibraryzombie{pointer_to_binary_function} \tcode{pointer_to_binary_function} \\ +\indexlibraryzombie{pointer_to_unary_function} \tcode{pointer_to_unary_function} \\ +\indexlibraryzombie{ptr_fun} \tcode{ptr_fun} \\ +\indexlibraryzombie{random_shuffle} \tcode{random_shuffle} \\ +\indexlibraryzombie{raw_storage_iterator} \tcode{raw_storage_iterator} \\ +\indexlibraryzombie{result_of} \tcode{result_of} \\ +\indexlibraryzombie{result_of_t} \tcode{result_of_t} \\ +\indexlibraryzombie{return_temporary_buffer} \tcode{return_temporary_buffer} \\ +\indexlibraryzombie{set_unexpected} \tcode{set_unexpected} \\ +\indexlibraryzombie{strstream} \tcode{strstream} \\ +\indexlibraryzombie{strstreambuf} \tcode{strstreambuf} \\ +\indexlibraryzombie{unary_function} \tcode{unary_function} \\ +\indexlibraryzombie{unary_negate} \tcode{unary_negate} \\ +\indexlibraryzombie{uncaught_exception} \tcode{uncaught_exception} \\ +\indexlibraryzombie{undeclare_no_pointers} \tcode{undeclare_no_pointers} \\ +\indexlibraryzombie{undeclare_reachable} \tcode{undeclare_reachable} \\ +\indexlibraryzombie{unexpected_handler} \tcode{unexpected_handler} \\ +\indexlibraryzombie{wbuffer_convert} \tcode{wbuffer_convert} \\ +\indexlibraryzombie{wstring_convert} \tcode{wstring_convert} \\ +\end{multicolfloattable} + \pnum -The following names are reserved as members for previous standardization, -and may not be used as a name for object-like macros in portable code: -\begin{itemize} -\item \indexlibraryzombie{argument_type} \tcode{argument_type}, -\item \indexlibraryzombie{first_argument_type} \tcode{first_argument_type}, -\item \indexlibraryzombie{io_state} \tcode{io_state}, -\item \indexlibraryzombie{op} \tcode{op}, -\item \indexlibraryzombie{open_mode} \tcode{open_mode}, -\item \indexlibraryzombie{preferred} \tcode{preferred}, -\item \indexlibraryzombie{second_argument_type} \tcode{second_argument_type}, -\item \indexlibraryzombie{seek_dir} \tcode{seek_dir}, and. -\item \indexlibraryzombie{strict} \tcode{strict}. -\end{itemize} +The names shown in \tref{zombie.names.objmacro} are reserved as members for +previous standardization, and may not be used as a name for object-like macros +in portable code: + +\begin{multicolfloattable}{Zombie object-like macros}{zombie.names.objmacro} +{lll} +\indexlibraryzombie{argument_type} \tcode{argument_type} \\ +\indexlibraryzombie{first_argument_type} \tcode{first_argument_type} \\ +\indexlibraryzombie{io_state} \tcode{io_state} \\ +\columnbreak +\indexlibraryzombie{op} \tcode{op} \\ +\indexlibraryzombie{open_mode} \tcode{open_mode} \\ +\indexlibraryzombie{preferred} \tcode{preferred} \\ +\columnbreak +\indexlibraryzombie{second_argument_type} \tcode{second_argument_type} \\ +\indexlibraryzombie{seek_dir} \tcode{seek_dir} \\ +\indexlibraryzombie{strict} \tcode{strict} \\ +\end{multicolfloattable} + \pnum -The name \indexlibraryzombie{stossc} \tcode{stossc} is reserved as a -member function for previous standardization, and may not be used as a name for -function-like macros in portable code. +The names shown in \tref{zombie.names.fnmacro} are reserved as member functions +for previous standardization, and may not be used as a name for function-like +macros in portable code: + +\begin{multicolfloattable}{Zombie function-like macros}{zombie.names.fnmacro} +{llllll} +\indexlibraryzombie{converted} \tcode{converted} \\ +\columnbreak +\indexlibraryzombie{freeze} \tcode{freeze} \\ +\columnbreak +\indexlibraryzombie{from_bytes} \tcode{from_bytes} \\ +\columnbreak +\indexlibraryzombie{pcount} \tcode{pcount} \\ +\columnbreak +\indexlibraryzombie{stossc} \tcode{stossc} \\ +\columnbreak +\indexlibraryzombie{to_bytes} \tcode{to_bytes} \\ +\end{multicolfloattable} \pnum -The header names -\libnoheader{ccomplex}, -\libnoheader{ciso646}, -\libnoheader{cstdalign}, -\libnoheader{cstdbool}, and -\libnoheader{ctgmath} -are reserved for previous standardization. +The header names shown in \tref{zombie.names.header} are reserved for previous +standardization: + +\begin{multicolfloattable}{Zombie headers}{zombie.names.header} +{lllll} +\libnoheader{ccomplex} \\ +\libnoheader{ciso646} \\ +\columnbreak +\libnoheader{codecvt} \\ +\libnoheader{cstdalign} \\ +\columnbreak +\libnoheader{cstdbool} \\ +\columnbreak +\libnoheader{ctgmath} \\ +\columnbreak +\libnoheader{strstream} \\ +\end{multicolfloattable} \rSec4[macro.names]{Macro names} @@ -3187,65 +3396,13 @@ \rSec3[replacement.functions]{Replacement functions} \pnum -\indextext{definition!alternate}% +If a function defined in \ref{\firstlibchapter} through \ref{\lastlibchapter} and \ref{depr} -describe the behavior of numerous functions defined by -the \Cpp{} standard library. -Under some circumstances, -\indextext{library!\Cpp{} standard}% -however, certain of these function descriptions also apply to replacement functions defined -in the program. - -\pnum -A \Cpp{} program may provide the definition for any of the following -dynamic memory allocation function signatures declared in header -\tcode{}\iref{basic.stc.dynamic,new.syn}: - -\indextext{\idxcode{new}!\idxcode{operator}!replaceable}% -\indexlibrarymember{new}{operator}% -\begin{codeblock} -operator new(std::size_t) -operator new(std::size_t, std::align_val_t) -operator new(std::size_t, const std::nothrow_t&) -operator new(std::size_t, std::align_val_t, const std::nothrow_t&) -\end{codeblock}% -\indextext{\idxcode{delete}!\idxcode{operator}!replaceable}% -\indexlibrarymember{delete}{operator}% -\begin{codeblock} -operator delete(void*) -operator delete(void*, std::size_t) -operator delete(void*, std::align_val_t) -operator delete(void*, std::size_t, std::align_val_t) -operator delete(void*, const std::nothrow_t&) -operator delete(void*, std::align_val_t, const std::nothrow_t&) -\end{codeblock}% -\indextext{\idxcode{new}!\idxcode{operator}!replaceable}% -\indexlibrarymember{new}{operator}% -\begin{codeblock} -operator new[](std::size_t) -operator new[](std::size_t, std::align_val_t) -operator new[](std::size_t, const std::nothrow_t&) -operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) -\end{codeblock}% -\indextext{\idxcode{delete}!\idxcode{operator}!replaceable}% -\indexlibrarymember{delete}{operator}% -\begin{codeblock} -operator delete[](void*) -operator delete[](void*, std::size_t) -operator delete[](void*, std::align_val_t) -operator delete[](void*, std::size_t, std::align_val_t) -operator delete[](void*, const std::nothrow_t&) -operator delete[](void*, std::align_val_t, const std::nothrow_t&) -\end{codeblock} +is specified as replaceable\iref{dcl.fct.def.replace}, +the description of function semantics apply +to both the default version defined by the \Cpp{} standard library and +the replacement function defined by the program. -\pnum -The program's definitions are used instead of the default versions supplied by -the implementation\iref{new.delete}. -Such replacement occurs prior to program startup\iref{basic.def.odr,basic.start}. -\indextext{startup!program}% -The program's declarations shall not be specified as -\keyword{inline}. -No diagnostic is required. \rSec3[handler.functions]{Handler functions} @@ -3284,8 +3441,8 @@ \end{itemize} \pnum -Calling the \tcode{set_*} and \tcode{get_*} functions shall not incur a data race. A call to -any of the \tcode{set_*} functions shall synchronize with subsequent calls to the same +Calling the \tcode{set_*} and \tcode{get_*} functions shall not incur a data race\iref{intro.races}. +A call to any of the \tcode{set_*} functions shall synchronize with subsequent calls to the same \tcode{set_*} function and to the corresponding \tcode{get_*} function. \rSec3[res.on.functions]{Other functions} @@ -3302,7 +3459,7 @@ \begin{itemize} \item -For replacement functions\iref{new.delete}, if the installed replacement function does not +For replacement functions\iref{replacement.functions}, if the installed replacement function does not implement the semantics of the applicable \required paragraph. @@ -3430,12 +3587,18 @@ Subclause \ref{conforming} describes the constraints upon, and latitude of, implementations of the \Cpp{} standard library. \pnum -An implementation's use of headers is discussed in~\ref{res.on.headers}, its use -of macros in~\ref{res.on.macro.definitions}, non-member functions -in~\ref{global.functions}, member functions in~\ref{member.functions}, data race -avoidance in~\ref{res.on.data.races}, access specifiers -in~\ref{protection.within.classes}, class derivation in~\ref{derivation}, and -exceptions in~\ref{res.on.exception.handling}. +An implementation's use of +\begin{itemize} +\item headers is discussed in~\ref{res.on.headers}, +\item macros in~\ref{res.on.macro.definitions}, +\item non-member functions in~\ref{global.functions}, +\item member functions in~\ref{member.functions}, +\item data race avoidance in~\ref{res.on.data.races}, +\item access specifiers in~\ref{protection.within.classes}, +\item class derivation in~\ref{derivation}, +\item exceptions in~\ref{res.on.exception.handling}, and +\item contract assertions in~\ref{res.contract.assertions}. +\end{itemize} \rSec3[res.on.headers]{Headers} @@ -3549,8 +3712,8 @@ provided by an implementation. \begin{note} In particular, -an implementation is not allowed to provide -an additional declaration of that function or function template +a conforming implementation does not provide +any additional declarations of that function or function template at namespace scope. \end{note} \begin{note} @@ -3655,6 +3818,28 @@ side effects. \end{note} +\rSec3[library.class.props]{Properties of library classes} + +\pnum +Unless explicitly stated otherwise, it is unspecified whether any class +described in \ref{\firstlibchapter} through \ref{\lastlibchapter} and +\ref{depr} is a trivially copyable class, a standard-layout class, or an +implicit-lifetime class\iref{class.prop}. + +\pnum +Unless explicitly stated otherwise, it is unspecified whether any class for +which trivial relocation (i.e., the effects of +\tcode{trivially_relocate}\iref{obj.lifetime}) would be semantically equivalent +to move-construction of the destination object followed by destruction of the +source object is a trivially relocatable class\iref{class.prop}. + +\pnum +Unless explicitly stated otherwise, it is unspecified whether a class \tcode{C} +is a replaceable class\iref{class.prop} if assigning an xvalue \tcode{a} of +type \tcode{C} to an object \tcode{b} of type \tcode{C} is semantically +equivalent to destroying \tcode{b} and then constructing from \tcode{a} in +\tcode{b}'s place. + \rSec3[protection.within.classes]{Protection within classes} \pnum @@ -3716,7 +3901,7 @@ can report a failure by throwing an exception of a type described in its \throws paragraph, or of a type derived from a type named in the \throws paragraph -that would be caught by an exception handler for the base type. +that would be caught by a \grammarterm{handler}\iref{except.handle} for the base type. \pnum Functions from the C standard library shall not throw exceptions% @@ -3740,7 +3925,7 @@ Destructor operations defined in the \Cpp{} standard library shall not throw exceptions. Every destructor in the \Cpp{} standard library shall behave as if it had a -non-throwing exception specification. +non-throwing exception specification\iref{except.spec}. \pnum Functions defined in the @@ -3768,6 +3953,15 @@ for a non-virtual function by adding a non-throwing exception specification. +\rSec3[res.contract.assertions]{Contract assertions} + +\pnum +Unless specified otherwise, +an implementation may check +the specified preconditions and postconditions of a function +in the \Cpp{} standard library using contract +assertions\iref{basic.contract,structure.specifications}. + \rSec3[value.error.codes]{Value of error codes} \pnum @@ -3795,7 +3989,7 @@ Objects of types defined in the \Cpp{} standard library may be moved from\iref{class.copy.ctor}. Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall -be placed in a valid but unspecified state. +be placed in a valid but unspecified state\iref{defns.valid}. \pnum An object of a type defined in the \Cpp{} standard library may be diff --git a/source/limits.tex b/source/limits.tex index 60c9dc3b69..bdc1f3deb6 100644 --- a/source/limits.tex +++ b/source/limits.tex @@ -1,22 +1,11 @@ %!TEX root = std.tex -\normannex{implimits}{Implementation quantities} +\infannex{implimits}{Implementation quantities} \pnum -Because computers are finite, \Cpp{} implementations are inevitably -limited in the size of the programs they can successfully process. -Every implementation shall -document those limitations where known. -This documentation may cite fixed limits where they -exist, say how to compute variable limits as a function -of available resources, or say that fixed limits do not exist -or are unknown. - -\pnum -The limits may constrain quantities -that include those described below or others. -The bracketed number following each quantity is recommended -as the minimum for that quantity. -However, these quantities are only guidelines and do not determine compliance. +Implementations can exhibit limitations for various quantities; +some possibilities are presented in the following list. +The bracketed number following each quantity is +a potential minimum value for that quantity. \begin{itemize} \item% Nesting levels of compound statements\iref{stmt.block}, diff --git a/source/locales.tex b/source/locales.tex deleted file mode 100644 index e36f215d68..0000000000 --- a/source/locales.tex +++ /dev/null @@ -1,5370 +0,0 @@ -%!TEX root = std.tex -\rSec0[localization]{Localization library} - -\rSec1[localization.general]{General} - -\pnum -This Clause describes components that \Cpp{} programs may use to -encapsulate (and therefore be more portable when confronting) -cultural differences. -The locale facility includes -internationalization support for character classification and string collation, -numeric, monetary, and date/time formatting and parsing, and -message retrieval. - -\pnum -The following subclauses describe components for -locales themselves, -the standard facets, and -facilities from the ISO C library, -as summarized in \tref{localization.summary}. - -\begin{libsumtab}{Localization library summary}{localization.summary} -\ref{locales} & Locales & \tcode{} \\ -\ref{locale.categories} & Standard \tcode{locale} categories & \\ \rowsep -\ref{c.locales} & C library locales & \tcode{} \\ \rowsep -\ref{text.encoding} & Text encodings identification & \tcode{} \\ -\end{libsumtab} - -\rSec1[locale.syn]{Header \tcode{} synopsis} - -\indexheader{locale}% -\begin{codeblock} -namespace std { - // \ref{locale}, locale - class locale; - template const Facet& use_facet(const locale&); - template bool has_facet(const locale&) noexcept; - - // \ref{locale.convenience}, convenience interfaces - template bool isspace (charT c, const locale& loc); - template bool isprint (charT c, const locale& loc); - template bool iscntrl (charT c, const locale& loc); - template bool isupper (charT c, const locale& loc); - template bool islower (charT c, const locale& loc); - template bool isalpha (charT c, const locale& loc); - template bool isdigit (charT c, const locale& loc); - template bool ispunct (charT c, const locale& loc); - template bool isxdigit(charT c, const locale& loc); - template bool isalnum (charT c, const locale& loc); - template bool isgraph (charT c, const locale& loc); - template bool isblank (charT c, const locale& loc); - template charT toupper(charT c, const locale& loc); - template charT tolower(charT c, const locale& loc); - - // \ref{category.ctype}, ctype - class ctype_base; - template class ctype; - template<> class ctype; // specialization - template class ctype_byname; - class codecvt_base; - template class codecvt; - template class codecvt_byname; - - // \ref{category.numeric}, numeric - template> - class num_get; - template> - class num_put; - template - class numpunct; - template - class numpunct_byname; - - // \ref{category.collate}, collation - template class collate; - template class collate_byname; - - // \ref{category.time}, date and time - class time_base; - template> - class time_get; - template> - class time_get_byname; - template> - class time_put; - template> - class time_put_byname; - - // \ref{category.monetary}, money - class money_base; - template> - class money_get; - template> - class money_put; - template - class moneypunct; - template - class moneypunct_byname; - - // \ref{category.messages}, message retrieval - class messages_base; - template class messages; - template class messages_byname; -} -\end{codeblock} - -\pnum -The header \libheader{locale} -defines classes and declares functions -that encapsulate and manipulate the information peculiar to a locale. -\begin{footnote} -In this subclause, the type name \tcode{tm} -is an incomplete type that is defined in \libheaderref{ctime}. -\end{footnote} - -\rSec1[locales]{Locales} - -\rSec2[locale]{Class \tcode{locale}} - -\rSec3[locale.general]{General} - -\begin{codeblock} -namespace std { - class locale { - public: - // \ref{locale.types}, types - // \ref{locale.facet}, class \tcode{locale::facet} - class facet; - // \ref{locale.id}, class \tcode{locale::id} - class id; - // \ref{locale.category}, type \tcode{locale::category} - using category = int; - static const category // values assigned here are for exposition only - none = 0, - collate = 0x010, ctype = 0x020, - monetary = 0x040, numeric = 0x080, - time = 0x100, messages = 0x200, - all = collate | ctype | monetary | numeric | time | messages; - - // \ref{locale.cons}, construct/copy/destroy - locale() noexcept; - locale(const locale& other) noexcept; - explicit locale(const char* std_name); - explicit locale(const string& std_name); - locale(const locale& other, const char* std_name, category); - locale(const locale& other, const string& std_name, category); - template locale(const locale& other, Facet* f); - locale(const locale& other, const locale& one, category); - ~locale(); // not virtual - const locale& operator=(const locale& other) noexcept; - - // \ref{locale.members}, locale operations - template locale combine(const locale& other) const; - string name() const; - text_encoding encoding() const; - - bool operator==(const locale& other) const; - - template - bool operator()(const basic_string& s1, - const basic_string& s2) const; - - // \ref{locale.statics}, global locale objects - static locale global(const locale&); - static const locale& classic(); - }; -} -\end{codeblock} - -\pnum -Class \tcode{locale} implements a type-safe polymorphic set of facets, -indexed by facet \textit{type}. -In other words, a facet has a dual role: -in one sense, it's just a class interface; -at the same time, it's an index into a locale's set of facets. - -\pnum -Access to the facets of a \tcode{locale} is via two function templates, -\tcode{use_facet<>} and \tcode{has_facet<>}. - -\pnum -\begin{example} -An iostream \tcode{operator<<} can be implemented as: -\begin{footnote} -Note that in the call to \tcode{put}, -the stream is implicitly converted -to an \tcode{ostreambuf_iterator}. -\end{footnote} - -\begin{codeblock} -template -basic_ostream& -operator<< (basic_ostream& s, Date d) { - typename basic_ostream::sentry cerberos(s); - if (cerberos) { - tm tmbuf; d.extract(tmbuf); - bool failed = - use_facet>>( - s.getloc()).put(s, s, s.fill(), &tmbuf, 'x').failed(); - if (failed) - s.setstate(s.badbit); // can throw - } - return s; -} -\end{codeblock} -\end{example} - -\pnum -In the call to \tcode{use_facet(loc)}, -the type argument chooses a facet, -making available all members of the named type. -If \tcode{Facet} is not present in a locale, -it throws the standard exception \tcode{bad_cast}. -A \Cpp{} program can check if a locale implements a particular facet -with the function template \tcode{has_facet()}. -User-defined facets may be installed in a locale, and -used identically as may standard facets. - -\pnum -\begin{note} -All locale semantics are accessed via -\tcode{use_facet<>} and \tcode{has_facet<>}, -except that: - -\begin{itemize} -\item -A member operator template -\begin{codeblock} -operator()(const basic_string&, const basic_string&) -\end{codeblock} -is provided so that a locale can be used as a predicate argument to -the standard collections, to collate strings. -\item -Convenient global interfaces are provided for -traditional \tcode{ctype} functions such as -\tcode{isdigit()} and \tcode{isspace()}, -so that given a locale object \tcode{loc} -a \Cpp{} program can call \tcode{isspace(c, loc)}. -(This eases upgrading existing extractors\iref{istream.formatted}.) -\end{itemize} -\end{note} - -\pnum -Once a facet reference is obtained from a locale object -by calling \tcode{use_facet<>}, -that reference remains usable, -and the results from member functions of it may be cached and re-used, -as long as some locale object refers to that facet. - -\pnum -In successive calls to a locale facet member function -on a facet object installed in the same locale, -the returned result shall be identical. - -\pnum -A \tcode{locale} constructed -from a name string (such as \tcode{"POSIX"}), or -from parts of two named locales, has a name; -all others do not. -Named locales may be compared for equality; -an unnamed locale is equal only to (copies of) itself. -For an unnamed locale, \tcode{locale::name()} returns the string \tcode{"*"}. - -\pnum -Whether there is -one global locale object for the entire program or -one global locale object per thread -is \impldef{whether locale object is global or per-thread}. -Implementations should provide one global locale object per thread. -If there is a single global locale object for the entire program, -implementations are not required to -avoid data races on it\iref{res.on.data.races}. - -\rSec3[locale.types]{Types} - -\rSec4[locale.category]{Type \tcode{locale::category}} - -\indexlibrarymember{locale}{category}% -\begin{itemdecl} -using category = int; -\end{itemdecl} - -\pnum -\textit{Valid} \tcode{category} values -include the \tcode{locale} member bitmask elements -\tcode{collate}, -\tcode{ctype}, -\tcode{monetary}, -\tcode{numeric}, -\tcode{time}, -and -\tcode{messages}, -each of which represents a single locale category. -In addition, \tcode{locale} member bitmask constant \tcode{none} -is defined as zero and represents no category. -And \tcode{locale} member bitmask constant \tcode{all} -is defined such that the expression -\begin{codeblock} -(collate | ctype | monetary | numeric | time | messages | all) == all -\end{codeblock} -is \tcode{true}, -and represents the union of all categories. -Further, the expression \tcode{(X | Y)}, -where \tcode{X} and \tcode{Y} each represent a single category, -represents the union of the two categories. - -\pnum -\tcode{locale} member functions -expecting a \tcode{category} argument -require one of the \tcode{category} values defined above, or -the union of two or more such values. -Such a \tcode{category} value identifies a set of locale categories. -Each locale category, in turn, identifies a set of locale facets, -including at least those shown in \tref{locale.category.facets}. - -\begin{floattable}{Locale category facets}{locale.category.facets} -{ll} -\topline -\lhdr{Category} & \rhdr{Includes facets} \\ \capsep -collate & \tcode{collate}, \tcode{collate} \\ \rowsep -ctype & \tcode{ctype}, \tcode{ctype} \\ - & \tcode{codecvt} \\ - & \tcode{codecvt} \\ - & \tcode{codecvt} \\ - & \tcode{codecvt} \\ \rowsep -monetary & \tcode{moneypunct}, \tcode{moneypunct} \\ - & \tcode{moneypunct}, \tcode{moneypunct} \\ - & \tcode{money_get}, \tcode{money_get} \\ - & \tcode{money_put}, \tcode{money_put} \\ \rowsep -numeric & \tcode{numpunct}, \tcode{numpunct} \\ - & \tcode{num_get}, \tcode{num_get} \\ - & \tcode{num_put}, \tcode{num_put} \\ \rowsep -time & \tcode{time_get}, \tcode{time_get} \\ - & \tcode{time_put}, \tcode{time_put} \\ \rowsep -messages & \tcode{messages}, \tcode{messages} \\ -\end{floattable} - -\pnum -For any locale \tcode{loc} -either constructed, or returned by \tcode{locale::classic()}, -and any facet \tcode{Facet} shown in \tref{locale.category.facets}, -\tcode{has_facet(loc)} is \tcode{true}. -Each \tcode{locale} member function -which takes a \tcode{locale::category} argument -operates on the corresponding set of facets. - -\pnum -An implementation is required to provide those specializations -for facet templates identified as members of a category, and -for those shown in \tref{locale.spec}. - -\begin{floattable}{Required specializations}{locale.spec} -{ll} -\topline -\lhdr{Category} & \rhdr{Includes facets} \\ \capsep -collate & \tcode{collate_byname}, \tcode{collate_byname} \\ \rowsep -ctype & \tcode{ctype_byname}, \tcode{ctype_byname} \\ - & \tcode{codecvt_byname} \\ - & \tcode{codecvt_byname} \\ - & \tcode{codecvt_byname} \\ - & \tcode{codecvt_byname} \\ \rowsep -monetary & \tcode{moneypunct_byname} \\ - & \tcode{moneypunct_byname} \\ - & \tcode{money_get} \\ - & \tcode{money_put} \\ \rowsep -numeric & \tcode{numpunct_byname}, \tcode{numpunct_byname} \\ - & \tcode{num_get}, \tcode{num_put} \\ \rowsep -time & \tcode{time_get} \\ - & \tcode{time_get_byname} \\ - & \tcode{time_get} \\ - & \tcode{time_get_byname} \\ - & \tcode{time_put} \\ - & \tcode{time_put_byname} \\ - & \tcode{time_put} \\ - & \tcode{time_put_byname} \\ \rowsep -messages & \tcode{messages_byname}, \tcode{messages_byname} \\ -\end{floattable} - - -\pnum -The provided implementation of members of -facets \tcode{num_get} and \tcode{num_put} -calls \tcode{use_fac\-et(l)} only for facet \tcode{F} of -types \tcode{numpunct} and \tcode{ctype}, -and for locale \tcode{l} the value obtained by calling member \tcode{getloc()} -on the \tcode{ios_base\&} argument to these functions. - -\pnum -In declarations of facets, -a template parameter with name \tcode{InputIterator} or \tcode{OutputIterator} -indicates the set of all possible specializations on parameters that meet the -\oldconcept{InputIterator} requirements or -\oldconcept{OutputIterator} requirements, -respectively\iref{iterator.requirements}. -A template parameter with name \tcode{C} represents -the set of types containing \keyword{char}, \keyword{wchar_t}, and any other -\impldef{set of character types -that iostreams templates can be instantiated for} -character types -that meet the requirements for a character -on which any of the iostream components can be instantiated. -A template parameter with name \tcode{International} -represents the set of all possible specializations on a bool parameter. - -\rSec4[locale.facet]{Class \tcode{locale::facet}} - -\indexlibrarymember{locale}{facet}% -\begin{codeblock} -namespace std { - class locale::facet { - protected: - explicit facet(size_t refs = 0); - virtual ~facet(); - facet(const facet&) = delete; - void operator=(const facet&) = delete; - }; -} -\end{codeblock} - -\pnum -Class \tcode{facet} is the base class for locale feature sets. -A class is a \defn{facet} -if it is publicly derived from another facet, or -if it is a class derived from \tcode{locale::facet} and -contains a publicly accessible declaration as follows: -\begin{footnote} -This is a complete list of requirements; there are no other requirements. -Thus, a facet class need not have a public -copy constructor, assignment, default constructor, destructor, etc. -\end{footnote} -\begin{codeblock} -static ::std::locale::id id; -\end{codeblock} - -\pnum -Template parameters in this Clause -which are required to be facets -are those named \tcode{Facet} in declarations. -A program that passes -a type that is \textit{not} a facet, or -a type that refers to a volatile-qualified facet, -as an (explicit or deduced) template parameter to -a locale function expecting a facet, -is ill-formed. -A const-qualified facet is a valid template argument to -any locale function that expects a \tcode{Facet} template parameter. - -\pnum -The \tcode{refs} argument to the constructor is used for lifetime management. -For \tcode{refs == 0}, -the implementation performs \tcode{delete static_cast(f)} -(where \tcode{f} is a point\-er to the facet) -when the last \tcode{locale} object containing the facet is destroyed; -for \tcode{refs == 1}, the implementation never destroys the facet. - -\pnum -Constructors of all facets defined in this Clause -take such an argument and pass it along to -their \tcode{facet} base class constructor. -All one-argument constructors defined in this Clause are \term{explicit}, -preventing their participation in implicit conversions. - -\pnum -For some standard facets a standard ``$\ldots$\tcode{_byname}'' class, -derived from it, implements the virtual function semantics -equivalent to that facet of the locale -constructed by \tcode{locale(const char*)} with the same name. -Each such facet provides a constructor that takes -a \tcode{const char*} argument, which names the locale, and -a \tcode{refs} argument, which is passed to the base class constructor. -Each such facet also provides a constructor that takes -a \tcode{string} argument \tcode{str} and -a \tcode{refs} argument, -which has the same effect as calling the first constructor -with the two arguments \tcode{str.c_str()} and \tcode{refs}. -If there is no ``$\ldots$\tcode{_byname}'' version of a facet, -the base class implements named locale semantics itself -by reference to other facets. - -\rSec4[locale.id]{Class \tcode{locale::id}} - -\indexlibrarymember{locale}{id}% -\begin{codeblock} -namespace std { - class locale::id { - public: - id(); - void operator=(const id&) = delete; - id(const id&) = delete; - }; -} -\end{codeblock} - -\pnum -The class \tcode{locale::id} provides -identification of a locale facet interface, -used as an index for lookup and to encapsulate initialization. - -\pnum -\begin{note} -Because facets are used by iostreams, -potentially while static constructors are running, -their initialization cannot depend on programmed static initialization. -One initialization strategy is for \tcode{locale} -to initialize each facet's \tcode{id} member -the first time an instance of the facet is installed into a locale. -This depends only on static storage being zero -before constructors run\iref{basic.start.static}. -\end{note} - -\rSec3[locale.cons]{Constructors and destructor} - -\indexlibraryctor{locale}% -\begin{itemdecl} -locale() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a copy of the argument last passed to -\tcode{locale::global(locale\&)}, -if it has been called; -else, the resulting facets have virtual function semantics identical to -those of \tcode{locale::classic()}. -\begin{note} -This constructor yields a copy of the current global locale. -It is commonly used as a default argument for -function parameters of type \tcode{const locale\&}. -\end{note} -\end{itemdescr} - -\indexlibraryctor{locale}% -\begin{itemdecl} -explicit locale(const char* std_name); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a locale using standard C locale names, e.g., \tcode{"POSIX"}. -The resulting locale implements semantics defined to be associated -with that name. - -\pnum -\throws -\tcode{runtime_error} if the argument is not valid, or is null. - -\pnum -\remarks -The set of valid string argument values is -\tcode{"C"}, \tcode{""}, and any \impldef{locale names} values. -\end{itemdescr} - -\indexlibraryctor{locale}% -\begin{itemdecl} -explicit locale(const string& std_name); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{locale(std_name.c_str())}. -\end{itemdescr} - -\indexlibraryctor{locale}% -\begin{itemdecl} -locale(const locale& other, const char* std_name, category cats); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{cats} is a valid \tcode{category} value\iref{locale.category}. - -\pnum -\effects -Constructs a locale as a copy of \tcode{other} -except for the facets identified by the \tcode{category} argument, -which instead implement the same semantics as \tcode{locale(std_name)}. - -\pnum -\throws -\tcode{runtime_error} if the second argument is not valid, or is null. - -\pnum -\remarks -The locale has a name if and only if \tcode{other} has a name. -\end{itemdescr} - -\indexlibraryctor{locale}% -\begin{itemdecl} -locale(const locale& other, const string& std_name, category cats); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{locale(other, std_name.c_str(), cats)}. -\end{itemdescr} - -\indexlibraryctor{locale}% -\begin{itemdecl} -template locale(const locale& other, Facet* f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a locale incorporating all facets from the first argument -except that of type \tcode{Facet}, -and installs the second argument as the remaining facet. -If \tcode{f} is null, the resulting object is a copy of \tcode{other}. - -\pnum -\remarks -If \tcode{f} is null, -the resulting locale has the same name as \tcode{other}. -Otherwise, the resulting locale has no name. -\end{itemdescr} - -\indexlibraryctor{locale}% -\begin{itemdecl} -locale(const locale& other, const locale& one, category cats); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{cats} is a valid \tcode{category} value. - -\pnum -\effects -Constructs a locale incorporating all facets from the first argument -except those that implement \tcode{cats}, -which are instead incorporated from the second argument. - -\pnum -\remarks -If \tcode{cats} is equal to \tcode{locale::none}, -the resulting locale has a name if and only if the first argument has a name. -Otherwise, the resulting locale has a name if and only if -the first two arguments both have names. -\end{itemdescr} - -\indexlibrarymember{operator=}{locale}% -\begin{itemdecl} -const locale& operator=(const locale& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Creates a copy of \tcode{other}, replacing the current value. - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\rSec3[locale.members]{Members} - -\indexlibrarymember{locale}{combine}% -\begin{itemdecl} -template locale combine(const locale& other) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a locale incorporating all facets from \tcode{*this} -except for that one facet of \tcode{other} that is identified by \tcode{Facet}. - -\pnum -\returns -The newly created locale. - -\pnum -\throws -\tcode{runtime_error} if \tcode{has_facet(other)} is \tcode{false}. - -\pnum -\remarks -The resulting locale has no name. -\end{itemdescr} - -\indexlibrarymember{locale}{name}% -\begin{itemdecl} -string name() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The name of \tcode{*this}, if it has one; -otherwise, the string \tcode{"*"}. -\end{itemdescr} - -\indexlibrarymember{locale}{encoding}% -\begin{itemdecl} -text_encoding encoding() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{CHAR_BIT == 8} is \tcode{true}. - -\pnum -\returns -A \tcode{text_encoding} object representing -the implementation-defined encoding scheme -associated with the locale \tcode{*this}. -\end{itemdescr} - -\rSec3[locale.operators]{Operators} - -\indexlibrarymember{locale}{operator==}% -\begin{itemdecl} -bool operator==(const locale& other) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if -both arguments are the same locale, or -one is a copy of the other, or -each has a name and the names are identical; -\tcode{false} otherwise. -\end{itemdescr} - -\indexlibrarymember{locale}{operator()}% -\begin{itemdecl} -template - bool operator()(const basic_string& s1, - const basic_string& s2) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Compares two strings according to the \tcode{collate} facet. - -\pnum -\returns -\begin{codeblock} -use_facet>(*this).compare(s1.data(), s1.data() + s1.size(), - s2.data(), s2.data() + s2.size()) < 0 -\end{codeblock} - -\pnum -\remarks -This member operator template (and therefore \tcode{locale} itself) -meets the requirements for -a comparator predicate template argument\iref{algorithms} applied to strings. - -\pnum -\begin{example} -A vector of strings \tcode{v} -can be collated according to collation rules in locale \tcode{loc} -simply by\iref{alg.sort,vector}: - -\begin{codeblock} -std::sort(v.begin(), v.end(), loc); -\end{codeblock} -\end{example} -\end{itemdescr} - -\rSec3[locale.statics]{Static members} - -\indexlibrarymember{locale}{global}% -\begin{itemdecl} -static locale global(const locale& loc); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Sets the global locale to its argument. -Causes future calls to the constructor \tcode{locale()} -to return a copy of the argument. -If the argument has a name, does -\begin{codeblock} -setlocale(LC_ALL, loc.name().c_str()); -\end{codeblock} -otherwise, the effect on the C locale, if any, is -\impldef{effect on C locale of calling \tcode{locale::global}}. - -\pnum -\returns -The previous value of \tcode{locale()}. - -\pnum -\remarks -No library function other than \tcode{locale::global()} -affects the value returned by \tcode{locale()}. -\begin{note} -See~\ref{c.locales} for data race considerations -when \tcode{setlocale} is invoked. -\end{note} -\end{itemdescr} - -\indexlibrarymember{locale}{classic}% -\begin{itemdecl} -static const locale& classic(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -The \tcode{"C"} locale. - -\pnum -\returns -A locale that implements the classic \tcode{"C"} locale semantics, -equivalent to the value \tcode{locale("C")}. - -\pnum -\remarks -This locale, its facets, and their member functions, do not change with time. -\end{itemdescr} - -\rSec2[locale.global.templates]{\tcode{locale} globals} - -\indexlibrarymember{locale}{use_facet}% -\begin{itemdecl} -template const Facet& use_facet(const locale& loc); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{Facet} is a facet class -whose definition contains the public static member \tcode{id} -as defined in~\ref{locale.facet}. - -\pnum -\returns -A reference to the corresponding facet of \tcode{loc}, if present. - -\pnum -\throws -\tcode{bad_cast} if \tcode{has_facet(loc)} is \tcode{false}. - -\pnum -\remarks -The reference returned remains valid -at least as long as any copy of \tcode{loc} exists. -\end{itemdescr} - -\indexlibrarymember{locale}{has_facet}% -\begin{itemdecl} -template bool has_facet(const locale& loc) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if the facet requested is present in \tcode{loc}; -otherwise \tcode{false}. -\end{itemdescr} - -\rSec2[locale.convenience]{Convenience interfaces} - -\rSec3[classification]{Character classification} - -\indexlibraryglobal{isspace}% -\indexlibraryglobal{isprint}% -\indexlibraryglobal{iscntrl}% -\indexlibraryglobal{isupper}% -\indexlibraryglobal{islower}% -\indexlibraryglobal{isalpha}% -\indexlibraryglobal{isdigit}% -\indexlibraryglobal{ispunct}% -\indexlibraryglobal{isxdigit}% -\indexlibraryglobal{isalnum}% -\indexlibraryglobal{isgraph}% -\indexlibraryglobal{isblank}% -\begin{itemdecl} -template bool isspace (charT c, const locale& loc); -template bool isprint (charT c, const locale& loc); -template bool iscntrl (charT c, const locale& loc); -template bool isupper (charT c, const locale& loc); -template bool islower (charT c, const locale& loc); -template bool isalpha (charT c, const locale& loc); -template bool isdigit (charT c, const locale& loc); -template bool ispunct (charT c, const locale& loc); -template bool isxdigit(charT c, const locale& loc); -template bool isalnum (charT c, const locale& loc); -template bool isgraph (charT c, const locale& loc); -template bool isblank (charT c, const locale& loc); -\end{itemdecl} - -\pnum -Each of these functions \tcode{is\placeholder{F}} -returns the result of the expression: -\begin{codeblock} -use_facet>(loc).is(ctype_base::@\placeholder{F}@, c) -\end{codeblock} -where \tcode{\placeholder{F}} is the \tcode{ctype_base::mask} value -corresponding to that function\iref{category.ctype}. -\begin{footnote} -When used in a loop, -it is faster to cache the \tcode{ctype<>} facet and use it directly, or -use the vector form of \tcode{ctype<>::is}. -\end{footnote} - -\rSec3[conversions.character]{Character conversions} - -\indexlibraryglobal{toupper}% -\begin{itemdecl} -template charT toupper(charT c, const locale& loc); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{use_facet>(loc).toupper(c)}. -\end{itemdescr} - -\indexlibraryglobal{tolower}% -\begin{itemdecl} -template charT tolower(charT c, const locale& loc); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{use_facet>(loc).tolower(c)}. -\end{itemdescr} - -\rSec1[locale.categories]{Standard \tcode{locale} categories} - -\rSec2[locale.categories.general]{General} - -\pnum -Each of the standard categories includes a family of facets. -Some of these implement formatting or parsing of a datum, -for use by standard or users' iostream operators \tcode{<<} and \tcode{>>}, -as members \tcode{put()} and \tcode{get()}, respectively. -Each such member function takes an -\indexlibrarymember{flags}{ios_base}% -\tcode{ios_base\&} argument whose members -\indexlibrarymember{flags}{ios_base}% -\tcode{flags()}, -\indexlibrarymember{precision}{ios_base}% -\tcode{precision()}, -and -\indexlibrarymember{width}{ios_base}% -\tcode{width()}, -specify the format of the corresponding datum\iref{ios.base}. -Those functions which need to use other facets call its member \tcode{getloc()} -to retrieve the locale imbued there. -Formatting facets use the character argument \tcode{fill} -to fill out the specified width where necessary. - -\pnum -The \tcode{put()} members make no provision for error reporting. -(Any failures of the OutputIterator argument can be extracted from -the returned iterator.) -The \tcode{get()} members take an \tcode{ios_base::iostate\&} argument -whose value they ignore, -but set to \tcode{ios_base::failbit} in case of a parse error. - -\pnum -Within subclause \ref{locale.categories} it is unspecified whether -one virtual function calls another virtual function. - -\rSec2[category.ctype]{The \tcode{ctype} category} - -\rSec3[category.ctype.general]{General} - -\indexlibraryglobal{ctype_base}% -\begin{codeblock} -namespace std { - class ctype_base { - public: - using mask = @\seebelow@; - - // numeric values are for exposition only. - static const mask space = 1 << 0; - static const mask print = 1 << 1; - static const mask cntrl = 1 << 2; - static const mask upper = 1 << 3; - static const mask lower = 1 << 4; - static const mask alpha = 1 << 5; - static const mask digit = 1 << 6; - static const mask punct = 1 << 7; - static const mask xdigit = 1 << 8; - static const mask blank = 1 << 9; - static const mask alnum = alpha | digit; - static const mask graph = alnum | punct; - }; -} -\end{codeblock} - -\pnum -The type \tcode{mask} is a bitmask type\iref{bitmask.types}. - -\rSec3[locale.ctype]{Class template \tcode{ctype}} - -\rSec4[locale.ctype.general]{General} - -\indexlibraryglobal{ctype}% -\begin{codeblock} -namespace std { - template - class ctype : public locale::facet, public ctype_base { - public: - using char_type = charT; - - explicit ctype(size_t refs = 0); - - bool is(mask m, charT c) const; - const charT* is(const charT* low, const charT* high, mask* vec) const; - const charT* scan_is(mask m, const charT* low, const charT* high) const; - const charT* scan_not(mask m, const charT* low, const charT* high) const; - charT toupper(charT c) const; - const charT* toupper(charT* low, const charT* high) const; - charT tolower(charT c) const; - const charT* tolower(charT* low, const charT* high) const; - - charT widen(char c) const; - const char* widen(const char* low, const char* high, charT* to) const; - char narrow(charT c, char dfault) const; - const charT* narrow(const charT* low, const charT* high, char dfault, char* to) const; - - static locale::id id; - - protected: - ~ctype(); - virtual bool do_is(mask m, charT c) const; - virtual const charT* do_is(const charT* low, const charT* high, mask* vec) const; - virtual const charT* do_scan_is(mask m, const charT* low, const charT* high) const; - virtual const charT* do_scan_not(mask m, const charT* low, const charT* high) const; - virtual charT do_toupper(charT) const; - virtual const charT* do_toupper(charT* low, const charT* high) const; - virtual charT do_tolower(charT) const; - virtual const charT* do_tolower(charT* low, const charT* high) const; - virtual charT do_widen(char) const; - virtual const char* do_widen(const char* low, const char* high, charT* dest) const; - virtual char do_narrow(charT, char dfault) const; - virtual const charT* do_narrow(const charT* low, const charT* high, - char dfault, char* dest) const; - }; -} -\end{codeblock} - -\pnum -Class \tcode{ctype} encapsulates the C library \libheader{cctype} features. -\tcode{istream} members are required to use \tcode{ctype<>} -for character classing during input parsing. - -\pnum -The specializations -required in \tref{locale.category.facets}\iref{locale.category}, -namely \tcode{ctype} and \tcode{ctype}, -implement character classing appropriate -to the implementation's native character set. - -\rSec4[locale.ctype.members]{\tcode{ctype} members} - -\indexlibrarymember{ctype}{is}% -\begin{itemdecl} -bool is(mask m, charT c) const; -const charT* is(const charT* low, const charT* high, mask* vec) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_is(m, c)} or \tcode{do_is(low, high, vec)}. -\end{itemdescr} - -\indexlibrarymember{ctype}{scan_is}% -\begin{itemdecl} -const charT* scan_is(mask m, const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_scan_is(m, low, high)}. -\end{itemdescr} - -\indexlibrarymember{ctype}{scan_not}% -\begin{itemdecl} -const charT* scan_not(mask m, const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_scan_not(m, low, high)}. -\end{itemdescr} - -\indexlibrarymember{ctype}{toupper}% -\begin{itemdecl} -charT toupper(charT) const; -const charT* toupper(charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_toupper(c)} or \tcode{do_toupper(low, high)}. -\end{itemdescr} - -\indexlibrarymember{ctype}{tolower}% -\begin{itemdecl} -charT tolower(charT c) const; -const charT* tolower(charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_tolower(c)} or \tcode{do_tolower(low, high)}. -\end{itemdescr} - -\indexlibrarymember{ctype}{widen}% -\begin{itemdecl} -charT widen(char c) const; -const char* widen(const char* low, const char* high, charT* to) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_widen(c)} or \tcode{do_widen(low, high, to)}. -\end{itemdescr} - -\indexlibrarymember{ctype}{narrow}% -\begin{itemdecl} -char narrow(charT c, char dfault) const; -const charT* narrow(const charT* low, const charT* high, char dfault, char* to) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_narrow(c, dfault)} or \tcode{do_narrow(low, high, dfault, to)}. -\end{itemdescr} - -\rSec4[locale.ctype.virtuals]{\tcode{ctype} virtual functions} - -\indexlibrarymember{ctype}{do_is}% -\begin{itemdecl} -bool do_is(mask m, charT c) const; -const charT* do_is(const charT* low, const charT* high, mask* vec) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Classifies a character or sequence of characters. -For each argument character, -identifies a value \tcode{M} of type \tcode{ctype_base::mask}. -The second form identifies a value \tcode{M} of type \tcode{ctype_base::mask} -for each \tcode{*p} where \tcode{(low <= p \&\& p < high)}, -and places it into \tcode{vec[p - low]}. - -\pnum -\returns -The first form returns the result of the expression \tcode{(M \& m) != 0}; -i.e., \tcode{true} if the character has the characteristics specified. -The second form returns \tcode{high}. -\end{itemdescr} - -\indexlibrarymember{ctype_base}{do_scan_is}% -\begin{itemdecl} -const charT* do_scan_is(mask m, const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Locates a character in a buffer that conforms to a classification \tcode{m}. - -\pnum -\returns -The smallest pointer \tcode{p} in the range \range{low}{high} -such that \tcode{is(m, *p)} would return \tcode{true}; -otherwise, returns \tcode{high}. -\end{itemdescr} - -\indexlibrarymember{ctype}{do_scan_not}% -\begin{itemdecl} -const charT* do_scan_not(mask m, const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Locates a character in a buffer that fails to conform to a classification -\tcode{m}. - -\pnum -\returns -The smallest pointer \tcode{p}, if any, in the range \range{low}{high} -such that \tcode{is(m, *p)} would return \tcode{false}; -otherwise, returns \tcode{high}. -\end{itemdescr} - -\indexlibrarymember{ctype}{do_toupper}% -\begin{itemdecl} -charT do_toupper(charT c) const; -const charT* do_toupper(charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Converts a character or characters to upper case. -The second form replaces -each character \tcode{*p} in the range \range{low}{high} -for which a corresponding upper-case character exists, -with that character. - -\pnum -\returns -The first form returns -the corresponding upper-case character if it is known to exist, or -its argument if not. -The second form returns \tcode{high}. -\end{itemdescr} - -\indexlibrarymember{ctype}{do_tolower}% -\begin{itemdecl} -charT do_tolower(charT c) const; -const charT* do_tolower(charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Converts a character or characters to lower case. -The second form replaces -each character \tcode{*p} in the range \range{low}{high} -and for which a corresponding lower-case character exists, -with that character. - -\pnum -\returns -The first form returns -the corresponding lower-case character if it is known to exist, or -its argument if not. -The second form returns \tcode{high}. -\end{itemdescr} - -\indexlibrarymember{ctype}{do_widen}% -\begin{itemdecl} -charT do_widen(char c) const; -const char* do_widen(const char* low, const char* high, charT* dest) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Applies the simplest reasonable transformation -from a \tcode{char} value or sequence of \tcode{char} values -to the corresponding \tcode{charT} value or values. -\begin{footnote} -The parameter \tcode{c} of \tcode{do_widen} is intended to -accept values derived from \grammarterm{character-literal}s -for conversion to the locale's encoding. -\end{footnote} -The only characters for which unique transformations are required -are those in the basic character set\iref{lex.charset}. - -For any named \tcode{ctype} category with -a \tcode{ctype} facet \tcode{ctc} and -valid \tcode{ctype_base::mask} value \tcode{M}, -\tcode{(ctc.\brk{}is(M, c) || !is(M, do_widen(c)) )} is \tcode{true}. -\begin{footnote} -In other words, the transformed character is not -a member of any character classification -that \tcode{c} is not also a member of. -\end{footnote} - -The second form transforms -each character \tcode{*p} in the range \range{low}{high}, -placing the result in \tcode{dest[p - low]}. - -\pnum -\returns -The first form returns the transformed value. -The second form returns \tcode{high}. -\end{itemdescr} - -\indexlibrarymember{ctype}{do_narrow}% -\begin{itemdecl} -char do_narrow(charT c, char dfault) const; -const charT* do_narrow(const charT* low, const charT* high, char dfault, char* dest) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Applies the simplest reasonable transformation -from a \tcode{charT} value or sequence of \tcode{charT} values -to the corresponding \tcode{char} value or values. - -For any character \tcode{c} in the basic character set\iref{lex.charset} -the transformation is such that -\begin{codeblock} -do_widen(do_narrow(c, 0)) == c -\end{codeblock} - -For any named \tcode{ctype} category with -a \tcode{ctype} facet \tcode{ctc} however, and -\tcode{ctype_base::mask} value \tcode{M}, -\begin{codeblock} -(is(M, c) || !ctc.is(M, do_narrow(c, dfault)) ) -\end{codeblock} -is \tcode{true} (unless \tcode{do_narrow} returns \tcode{dfault}). -In addition, for any digit character \tcode{c}, -the expression \tcode{(do_narrow(c, dfault) - '0')} -evaluates to the digit value of the character. -The second form transforms -each character \tcode{*p} in the range \range{low}{high}, -placing the result -(or \tcode{dfault} if no simple transformation is readily available) -in \tcode{dest[p - low]}. - -\pnum -\returns -The first form returns the transformed value; -or \tcode{dfault} if no mapping is readily available. -The second form returns \tcode{high}. -\end{itemdescr} - -\rSec3[locale.ctype.byname]{Class template \tcode{ctype_byname}} - -\indexlibraryglobal{ctype_byname}% -\begin{codeblock} -namespace std { - template - class ctype_byname : public ctype { - public: - using mask = typename ctype::mask; - explicit ctype_byname(const char*, size_t refs = 0); - explicit ctype_byname(const string&, size_t refs = 0); - - protected: - ~ctype_byname(); - }; -} -\end{codeblock} - -\rSec3[facet.ctype.special]{\tcode{ctype} specialization} - -\rSec4[facet.ctype.special.general]{General} - -\indexlibraryglobal{ctype}% -\begin{codeblock} -namespace std { - template<> - class ctype : public locale::facet, public ctype_base { - public: - using char_type = char; - - explicit ctype(const mask* tab = nullptr, bool del = false, size_t refs = 0); - - bool is(mask m, char c) const; - const char* is(const char* low, const char* high, mask* vec) const; - const char* scan_is (mask m, const char* low, const char* high) const; - const char* scan_not(mask m, const char* low, const char* high) const; - - char toupper(char c) const; - const char* toupper(char* low, const char* high) const; - char tolower(char c) const; - const char* tolower(char* low, const char* high) const; - - char widen(char c) const; - const char* widen(const char* low, const char* high, char* to) const; - char narrow(char c, char dfault) const; - const char* narrow(const char* low, const char* high, char dfault, char* to) const; - - static locale::id id; - static const size_t table_size = @\impdef@; - - const mask* table() const noexcept; - static const mask* classic_table() noexcept; - - protected: - ~ctype(); - virtual char do_toupper(char c) const; - virtual const char* do_toupper(char* low, const char* high) const; - virtual char do_tolower(char c) const; - virtual const char* do_tolower(char* low, const char* high) const; - - virtual char do_widen(char c) const; - virtual const char* do_widen(const char* low, const char* high, char* to) const; - virtual char do_narrow(char c, char dfault) const; - virtual const char* do_narrow(const char* low, const char* high, - char dfault, char* to) const; - }; -} -\end{codeblock} - -\pnum -A specialization \tcode{ctype} is provided -so that the member functions on type \tcode{char} can be implemented inline. -\begin{footnote} -Only the \tcode{char} (not \tcode{unsigned char} and \tcode{signed char}) -form is provided. -The specialization is specified in the standard, -and not left as an implementation detail, -because it affects the derivation interface for \tcode{ctype}. -\end{footnote} -The \impldef{value of \tcode{ctype::table_size}} value of -member \tcode{table_size} is at least 256. - -\rSec4[facet.ctype.char.dtor]{Destructor} - -\indexlibrarydtor{ctype}% -\begin{itemdecl} -~ctype(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If the constructor's first argument was nonzero, and -its second argument was \tcode{true}, -does \tcode{delete [] table()}. -\end{itemdescr} - -\rSec4[facet.ctype.char.members]{Members} - -\pnum -\indexlibrarymember{ctype}{ctype}% -In the following member descriptions, -for \tcode{unsigned char} values \tcode{v} where \tcode{v >= table_size}, -\tcode{table()[v]} is assumed to have an implementation-specific value -(possibly different for each such value \tcode{v}) -without performing the array lookup. - -\indexlibraryctor{ctype}% -\begin{itemdecl} -explicit ctype(const mask* tbl = nullptr, bool del = false, size_t refs = 0); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -Either \tcode{tbl == nullptr} is \tcode{true} or -\range{tbl}{tbl+table_size} is a valid range. - -\pnum -\effects -Passes its \tcode{refs} argument to its base class constructor. -\end{itemdescr} - -\indexlibrarymember{ctype}{is}% -\begin{itemdecl} -bool is(mask m, char c) const; -const char* is(const char* low, const char* high, mask* vec) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -The second form, for all \tcode{*p} in the range \range{low}{high}, -assigns into \tcode{vec[p - low]} the value \tcode{table()[(unsigned char)*p]}. - -\pnum -\returns -The first form returns \tcode{table()[(unsigned char)c] \& m}; -the second form returns \tcode{high}. -\end{itemdescr} - -\indexlibrarymember{ctype}{scan_is}% -\begin{itemdecl} -const char* scan_is(mask m, const char* low, const char* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The smallest \tcode{p} in the range \range{low}{high} such that -\begin{codeblock} -table()[(unsigned char) *p] & m -\end{codeblock} -is \tcode{true}. -\end{itemdescr} - -\indexlibrarymember{ctype}{scan_not}% -\begin{itemdecl} -const char* scan_not(mask m, const char* low, const char* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The smallest \tcode{p} in the range \range{low}{high} such that -\begin{codeblock} -table()[(unsigned char) *p] & m -\end{codeblock} -is \tcode{false}. -\end{itemdescr} - -\indexlibrarymember{ctype}{toupper}% -\begin{itemdecl} -char toupper(char c) const; -const char* toupper(char* low, const char* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_toupper(c)} or \tcode{do_toupper(low, high)}, respectively. -\end{itemdescr} - -\indexlibrarymember{ctype}{tolower}% -\begin{itemdecl} -char tolower(char c) const; -const char* tolower(char* low, const char* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_tolower(c)} or \tcode{do_tolower(low, high)}, respectively. -\end{itemdescr} - -\indexlibrarymember{ctype}{widen}% -\begin{itemdecl} -char widen(char c) const; -const char* widen(const char* low, const char* high, char* to) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_widen(c)} or -\indexlibraryglobal{do_widen}% -\tcode{do_widen(low, high, to)}, respectively. -\end{itemdescr} - -\indexlibrarymember{ctype}{narrow}% -\begin{itemdecl} -char narrow(char c, char dfault) const; -const char* narrow(const char* low, const char* high, char dfault, char* to) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\indexlibraryglobal{do_narrow}% -\tcode{do_narrow(c, dfault)} or -\indexlibraryglobal{do_narrow}% -\tcode{do_narrow(low, high, dfault, to)}, -respectively. -\end{itemdescr} - -\indexlibrarymember{ctype}{table}% -\begin{itemdecl} -const mask* table() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The first constructor argument, if it was nonzero, -otherwise \tcode{classic_table()}. -\end{itemdescr} - -\rSec4[facet.ctype.char.statics]{Static members} - -\indexlibrarymember{ctype}{classic_table}% -\begin{itemdecl} -static const mask* classic_table() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A pointer to the initial element of an array of size \tcode{table_size} -which represents the classifications of characters in the \tcode{"C"} locale. -\end{itemdescr} - -\rSec4[facet.ctype.char.virtuals]{Virtual functions} - -\indexlibrarymember{ctype}{do_toupper}% -\indexlibrarymember{ctype}{do_tolower}% -\indexlibrarymember{ctype}{do_widen}% -\indexlibrarymember{ctype}{do_narrow}% -\begin{codeblock} -char do_toupper(char) const; -const char* do_toupper(char* low, const char* high) const; -char do_tolower(char) const; -const char* do_tolower(char* low, const char* high) const; - -virtual char do_widen(char c) const; -virtual const char* do_widen(const char* low, const char* high, char* to) const; -virtual char do_narrow(char c, char dfault) const; -virtual const char* do_narrow(const char* low, const char* high, - char dfault, char* to) const; -\end{codeblock} - -\pnum -These functions are described identically as those members of the same name -in the \tcode{ctype} class template\iref{locale.ctype.members}. - -\rSec3[locale.codecvt]{Class template \tcode{codecvt}} - -\rSec4[locale.codecvt.general]{General} - -\indexlibraryglobal{codecvt}% -\begin{codeblock} -namespace std { - class codecvt_base { - public: - enum result { ok, partial, error, noconv }; - }; - - template - class codecvt : public locale::facet, public codecvt_base { - public: - using intern_type = internT; - using extern_type = externT; - using state_type = stateT; - - explicit codecvt(size_t refs = 0); - - result out( - stateT& state, - const internT* from, const internT* from_end, const internT*& from_next, - externT* to, externT* to_end, externT*& to_next) const; - - result unshift( - stateT& state, - externT* to, externT* to_end, externT*& to_next) const; - - result in( - stateT& state, - const externT* from, const externT* from_end, const externT*& from_next, - internT* to, internT* to_end, internT*& to_next) const; - - int encoding() const noexcept; - bool always_noconv() const noexcept; - int length(stateT&, const externT* from, const externT* end, size_t max) const; - int max_length() const noexcept; - - static locale::id id; - - protected: - ~codecvt(); - virtual result do_out( - stateT& state, - const internT* from, const internT* from_end, const internT*& from_next, - externT* to, externT* to_end, externT*& to_next) const; - virtual result do_in( - stateT& state, - const externT* from, const externT* from_end, const externT*& from_next, - internT* to, internT* to_end, internT*& to_next) const; - virtual result do_unshift( - stateT& state, - externT* to, externT* to_end, externT*& to_next) const; - - virtual int do_encoding() const noexcept; - virtual bool do_always_noconv() const noexcept; - virtual int do_length(stateT&, const externT* from, const externT* end, size_t max) const; - virtual int do_max_length() const noexcept; - }; -} -\end{codeblock} - -\pnum -The class \tcode{codecvt} is for use -when converting from one character encoding to another, -such as from wide characters to multibyte characters or -between wide character encodings such as UTF-32 and EUC. - -\pnum -The \tcode{stateT} argument selects -the pair of character encodings being mapped between. - -\pnum -The specializations required -in \tref{locale.category.facets}\iref{locale.category} -convert the implementation-defined native character set. -\tcode{codecvt} implements a degenerate conversion; -it does not convert at all. -\indextext{UTF-8}% -\indextext{UTF-16}% -\indextext{UTF-32}% -The specialization \tcode{codecvt} -converts between the UTF-16 and UTF-8 encoding forms, and -the specialization \tcode{codecvt} -converts between the UTF-32 and UTF-8 encoding forms. -\tcode{codecvt} -converts between the native character sets for ordinary and wide characters. -Specializations on \tcode{mbstate_t} -perform conversion between encodings known to the library implementer. -Other encodings can be converted by specializing on -a program-defined \tcode{stateT} type. -Objects of type \tcode{stateT} can contain any state -that is useful to communicate to or from -the specialized \tcode{do_in} or \tcode{do_out} members. - -\rSec4[locale.codecvt.members]{Members} - -\indexlibrarymember{codecvt}{out}% -\begin{itemdecl} -result out( - stateT& state, - const internT* from, const internT* from_end, const internT*& from_next, - externT* to, externT* to_end, externT*& to_next) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_out(state, from, from_end, from_next, to, to_end, to_next)}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{unshift}% -\begin{itemdecl} -result unshift(stateT& state, externT* to, externT* to_end, externT*& to_next) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_unshift(state, to, to_end, to_next)}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{in}% -\begin{itemdecl} -result in( - stateT& state, - const externT* from, const externT* from_end, const externT*& from_next, - internT* to, internT* to_end, internT*& to_next) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_in(state, from, from_end, from_next, to, to_end, to_next)}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{encoding}% -\begin{itemdecl} -int encoding() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_encoding()}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{always_noconv}% -\begin{itemdecl} -bool always_noconv() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_always_noconv()}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{length}% -\begin{itemdecl} -int length(stateT& state, const externT* from, const externT* from_end, size_t max) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_length(state, from, from_end, max)}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{max_length}% -\begin{itemdecl} -int max_length() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_max_length()}. -\end{itemdescr} - -\rSec4[locale.codecvt.virtuals]{Virtual functions} - -\indexlibrarymember{codecvt}{do_out}% -\indexlibrarymember{codecvt}{do_in}% -\begin{itemdecl} -result do_out( - stateT& state, - const internT* from, const internT* from_end, const internT*& from_next, - externT* to, externT* to_end, externT*& to_next) const; - -result do_in( - stateT& state, - const externT* from, const externT* from_end, const externT*& from_next, - internT* to, internT* to_end, internT*& to_next) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{(from <= from_end \&\& to <= to_end)} is well-defined and \tcode{true}; -\tcode{state} is initialized, if at the beginning of a sequence, -or else is equal to the result of converting -the preceding characters in the sequence. - -\pnum -\effects -Translates characters in the source range \range{from}{from_end}, -placing the results in sequential positions starting at destination \tcode{to}. -Converts no more than \tcode{(from_end - from)} source elements, and -stores no more than \tcode{(to_end - to)} destination elements. - -\pnum -Stops if it encounters a character it cannot convert. -It always leaves the \tcode{from_next} and \tcode{to_next} pointers -pointing one beyond the last element successfully converted. -If returns \tcode{noconv}, -\tcode{internT} and \tcode{externT} are the same type and -the converted sequence is identical to -the input sequence \range{from}{from\textunderscore\nobreak next}. -\tcode{to_next} is set equal to \tcode{to}, -the value of \tcode{state} is unchanged, and -there are no changes to the values in \range{to}{to_end}. - -\pnum -A \tcode{codecvt} facet -that is used by \tcode{basic_filebuf}\iref{file.streams} -shall have the property that if -\begin{codeblock} -do_out(state, from, from_end, from_next, to, to_end, to_next) -\end{codeblock} -would return \tcode{ok}, -where \tcode{from != from_end}, -then -\begin{codeblock} -do_out(state, from, from + 1, from_next, to, to_end, to_next) -\end{codeblock} -shall also return \tcode{ok}, -and that if -\begin{codeblock} -do_in(state, from, from_end, from_next, to, to_end, to_next) -\end{codeblock} -would return \tcode{ok}, -where \tcode{to != to_end}, -then -\begin{codeblock} -do_in(state, from, from_end, from_next, to, to + 1, to_next) -\end{codeblock} -shall also return \tcode{ok}. -\begin{footnote} -Informally, this means that \tcode{basic_filebuf} -assumes that the mappings from internal to external characters is 1 to N: -that a \tcode{codecvt} facet that is used by \tcode{basic_filebuf} -can translate characters one internal character at a time. -\end{footnote} -\begin{note} -As a result of operations on \tcode{state}, -it can return \tcode{ok} or \tcode{partial} and -set \tcode{from_next == from} and \tcode{to_next != to}. -\end{note} - -\pnum -\returns -An enumeration value, as summarized in \tref{locale.codecvt.inout}. - -\begin{floattable}{\tcode{do_in/do_out} result values}{locale.codecvt.inout} -{lp{3in}} -\topline -\lhdr{Value} & \rhdr{Meaning} \\ \capsep -\tcode{ok} & completed the conversion \\ -\tcode{partial} & not all source characters converted \\ -\tcode{error} & -encountered a character in \range{from}{from_end} -that cannot be converted \\ -\tcode{noconv} & -\tcode{internT} and \tcode{externT} are the same type, and input -sequence is identical to converted sequence \\ -\end{floattable} - -A return value of \tcode{partial}, -if \tcode{(from_next == from_end)}, -indicates -that either the destination sequence has not absorbed -all the available destination elements, or -that additional source elements are needed -before another destination element can be produced. - -\pnum -\remarks -Its operations on \tcode{state} are unspecified. -\begin{note} -This argument can be used, for example, -to maintain shift state, -to specify conversion options (such as count only), or -to identify a cache of seek offsets. -\end{note} -\end{itemdescr} - -\indexlibrarymember{codecvt}{do_unshift}% -\begin{itemdecl} -result do_unshift(stateT& state, externT* to, externT* to_end, externT*& to_next) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{(to <= to_end)} is well-defined and \tcode{true}; -\tcode{state} is initialized, if at the beginning of a sequence, -or else is equal to the result of converting -the preceding characters in the sequence. - -\pnum -\effects -Places characters starting at \tcode{to} -that should be appended to terminate a sequence -when the current \tcode{stateT} is given by \tcode{state}. -\begin{footnote} -Typically these will be characters to return the state to \tcode{stateT()}. -\end{footnote} -Stores no more than \tcode{(to_end - to)} destination elements, and -leaves the \tcode{to_next} pointer -pointing one beyond the last element successfully stored. - -\pnum -\returns -An enumeration value, as summarized in \tref{locale.codecvt.unshift}. - -\begin{floattable}{\tcode{do_unshift} result values}{locale.codecvt.unshift} -{lp{.50\hsize}} -\topline -\lhdr{Value} & \rhdr{Meaning} \\ \capsep -\tcode{ok} & completed the sequence \\ -\tcode{partial} & -space for more than \tcode{to_end - to} destination elements was needed -to terminate a sequence given the value of \tcode{state}\\ -\tcode{error} & an unspecified error has occurred \\ -\tcode{noconv} & no termination is needed for this \tcode{state_type} \\ -\end{floattable} -\end{itemdescr} - -\indexlibrarymember{codecvt}{do_encoding}% -\begin{itemdecl} -int do_encoding() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{-1} if the encoding of the \tcode{externT} sequence is state-dependent; -else the constant number of \tcode{externT} characters -needed to produce an internal character; -or \tcode{0} if this number is not a constant. -\begin{footnote} -If \tcode{encoding()} yields \tcode{-1}, -then more than \tcode{max_length()} \tcode{externT} elements -can be consumed when producing a single \tcode{internT} character, and -additional \tcode{externT} elements can appear at the end of a sequence -after those that yield the final \tcode{internT} character. -\end{footnote} -\end{itemdescr} - -\indexlibrarymember{codecvt}{do_always_noconv}% -\begin{itemdecl} -bool do_always_noconv() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if \tcode{do_in()} and \tcode{do_out()} return \tcode{noconv} -for all valid argument values. -\tcode{codecvt} returns \tcode{true}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{do_length}% -\begin{itemdecl} -int do_length(stateT& state, const externT* from, const externT* from_end, size_t max) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{(from <= from_end)} is well-defined and \tcode{true}; -\tcode{state} is initialized, if at the beginning of a sequence, -or else is equal to the result of converting -the preceding characters in the sequence. - -\pnum -\effects -The effect on the \tcode{state} argument is as if -it called \tcode{do_in(state, from, from_end, from, to, to+max, to)} -for \tcode{to} pointing to a buffer of at least \tcode{max} elements. - -\pnum -\returns -\tcode{(from_next-from)} where -\tcode{from_next} is the largest value in the range \crange{from}{from_end} -such that the sequence of values in the range \range{from}{from_next} -represents -\tcode{max} or fewer valid complete characters of type \tcode{internT}. -The specialization \tcode{codecvt}, -returns the lesser of \tcode{max} and \tcode{(from_end-from)}. -\end{itemdescr} - -\indexlibrarymember{codecvt}{do_max_length}% -\begin{itemdecl} -int do_max_length() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The maximum value that \tcode{do_length(state, from, from_end, 1)} can return -for any valid range \range{from}{from_end} -and \tcode{stateT} value \tcode{state}. -The specialization \tcode{codecvt::do_max_length()} -returns 1. -\end{itemdescr} - -\rSec3[locale.codecvt.byname]{Class template \tcode{codecvt_byname}} - -\indexlibraryglobal{codecvt_byname}% -\begin{codeblock} -namespace std { - template - class codecvt_byname : public codecvt { - public: - explicit codecvt_byname(const char*, size_t refs = 0); - explicit codecvt_byname(const string&, size_t refs = 0); - - protected: - ~codecvt_byname(); - }; -} -\end{codeblock} - -\rSec2[category.numeric]{The numeric category} - -\rSec3[category.numeric.general]{General} - -\pnum -The classes \tcode{num_get<>} and \tcode{num_put<>} -handle numeric formatting and parsing. -Virtual functions are provided for several numeric types. -Implementations may (but are not required to) delegate -extraction of smaller types to extractors for larger types. -\begin{footnote} -Parsing \tcode{"-1"} correctly into, e.g., an \tcode{unsigned short} -requires that the corresponding member \tcode{get()} -at least extract the sign before delegating. -\end{footnote} - -\pnum -All specifications of member functions for \tcode{num_put} and \tcode{num_get} -in the subclauses of~\ref{category.numeric} only apply to -the specializations required in Tables~\ref{tab:locale.category.facets} -and~\ref{tab:locale.spec}\iref{locale.category}, namely -\tcode{num_get}, -\tcode{num_get}, -\tcode{num_get}, -\tcode{num_put}, -\tcode{num_put}, and -\tcode{num_put}. -These specializations refer to the \tcode{ios_base\&} argument for -formatting specifications\iref{locale.categories}, -and to its imbued locale for the \tcode{numpunct<>} facet to -identify all numeric punctuation preferences, -and also for the \tcode{ctype<>} facet to perform character classification. - -\pnum -Extractor and inserter members of the standard iostreams use -\tcode{num_get<>} and \tcode{num_put<>} member functions for -formatting and parsing -numeric values\iref{istream.formatted.reqmts,ostream.formatted.reqmts}. - -\rSec3[locale.num.get]{Class template \tcode{num_get}} - -\rSec4[locale.num.get.general]{General} - -\indexlibraryglobal{num_get}% -\begin{codeblock} -namespace std { - template> - class num_get : public locale::facet { - public: - using char_type = charT; - using iter_type = InputIterator; - - explicit num_get(size_t refs = 0); - - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, bool& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, long& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, long long& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, unsigned short& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, unsigned int& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, unsigned long& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, unsigned long long& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, float& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, double& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, long double& v) const; - iter_type get(iter_type in, iter_type end, ios_base&, - ios_base::iostate& err, void*& v) const; - - static locale::id id; - - protected: - ~num_get(); - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, bool& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, long& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, long long& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, unsigned short& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, unsigned int& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, unsigned long& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, unsigned long long& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, float& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, double& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, long double& v) const; - virtual iter_type do_get(iter_type, iter_type, ios_base&, - ios_base::iostate& err, void*& v) const; - }; -} -\end{codeblock} - -\pnum -The facet \tcode{num_get} is used to parse numeric values -from an input sequence such as an istream. - -\rSec4[facet.num.get.members]{Members} - -\indexlibrarymember{num_get}{get}% -\begin{itemdecl} -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, bool& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, long& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, long long& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned short& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned int& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned long& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned long long& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, float& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, double& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, long double& val) const; -iter_type get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, void*& val) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get(in, end, str, err, val)}. -\end{itemdescr} - -\rSec4[facet.num.get.virtuals]{Virtual functions} - -\indexlibrarymember{num_get}{do_get}% -\begin{itemdecl} -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, long& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, long long& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned short& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned int& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned long& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, unsigned long long& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, float& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, double& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, long double& val) const; -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, void*& val) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Reads characters from \tcode{in}, -interpreting them according to -\tcode{str.flags()}, -\tcode{use_facet>(loc)}, and -\tcode{use_facet>(loc)}, -where \tcode{loc} is \tcode{str.getloc()}. - -\pnum -The details of this operation occur in three stages - -\begin{itemize} -\item -Stage 1: -Determine a conversion specifier -\item -Stage 2: -Extract characters from \tcode{in} and -determine a corresponding \tcode{char} value for -the format expected by the conversion specification determined in stage 1. -\item -Stage 3: -Store results -\end{itemize} - -\pnum -The details of the stages are presented below. - -\begin{description} -\stage{1} -The function initializes local variables via -\begin{codeblock} -fmtflags flags = str.flags(); -fmtflags basefield = (flags & ios_base::basefield); -fmtflags uppercase = (flags & ios_base::uppercase); -fmtflags boolalpha = (flags & ios_base::boolalpha); -\end{codeblock} - -For conversion to an integral type, -the function determines the integral conversion specifier -as indicated in \tref{facet.num.get.int}. -The table is ordered. -That is, the first line whose condition is true applies. - -\begin{floattable}{Integer conversions}{facet.num.get.int} -{lc} -\topline -\lhdr{State} & \tcode{stdio} equivalent \\ \capsep -\tcode{basefield == oct} & \tcode{\%o} \\ \rowsep -\tcode{basefield == hex} & \tcode{\%X} \\ \rowsep -\tcode{basefield == 0} & \tcode{\%i} \\ \capsep -\tcode{signed} integral type & \tcode{\%d} \\ \rowsep -\tcode{unsigned} integral type & \tcode{\%u} \\ -\end{floattable} - -For conversions to a floating-point type the specifier is \tcode{\%g}. - -For conversions to \tcode{void*} the specifier is \tcode{\%p}. - -A length modifier is added to the conversion specification, if needed, -as indicated in \tref{facet.num.get.length}. - -\begin{floattable}{Length modifier}{facet.num.get.length} -{lc} -\topline -\lhdr{Type} & Length modifier \\ \capsep -\tcode{short} & \tcode{h} \\ \rowsep -\tcode{unsigned short} & \tcode{h} \\ \rowsep -\tcode{long} & \tcode{l} \\ \rowsep -\tcode{unsigned long} & \tcode{l} \\ \rowsep -\tcode{long long} & \tcode{ll} \\ \rowsep -\tcode{unsigned long long} & \tcode{ll} \\ \rowsep -\tcode{double} & \tcode{l} \\ \rowsep -\tcode{long double} & \tcode{L} \\ -\end{floattable} - -\stage{2} -If \tcode{in == end} then stage 2 terminates. -Otherwise a \tcode{charT} is taken from \tcode{in} and -local variables are initialized as if by -\begin{codeblock} -char_type ct = *in; -char c = src[find(atoms, atoms + sizeof(src) - 1, ct) - atoms]; -if (ct == use_facet>(loc).decimal_point()) - c = '.'; -bool discard = - ct == use_facet>(loc).thousands_sep() - && use_facet>(loc).grouping().length() != 0; -\end{codeblock} -where the values \tcode{src} and \tcode{atoms} are defined as if by: -\begin{codeblock} -static const char src[] = "0123456789abcdefpxABCDEFPX+-"; -char_type atoms[sizeof(src)]; -use_facet>(loc).widen(src, src + sizeof(src), atoms); -\end{codeblock} -for this value of \tcode{loc}. - -If \tcode{discard} is \tcode{true}, -then if \tcode{'.'} has not yet been accumulated, -then the position of the character is remembered, -but the character is otherwise ignored. -Otherwise, if \tcode{'.'} has already been accumulated, -the character is discarded and Stage 2 terminates. -If it is not discarded, -then a check is made to determine -if \tcode{c} is allowed as the next character of -an input field of the conversion specifier returned by Stage 1. -If so, it is accumulated. - -If the character is either discarded or accumulated -then \tcode{in} is advanced by \tcode{++in} -and processing returns to the beginning of stage 2. - -\begin{example} -Given an input sequence of \tcode{"0x1a.bp+07p"}, -\begin{itemize} -\item -if the conversion specifier returned by Stage 1 is \tcode{\%d}, -\tcode{"0"} is accumulated; -\item -if the conversion specifier returned by Stage 1 is \tcode{\%i}, -\tcode{"0x1a"} are accumulated; -\item -if the conversion specifier returned by Stage 1 is \tcode{\%g}, -\tcode{"0x1a.bp+07"} are accumulated. -\end{itemize} -In all cases, the remainder is left in the input. -\end{example} - -\stage{3} -The sequence of \tcode{char}{s} accumulated in stage 2 (the field) -is converted to a numeric value by the rules of one of the functions -declared in the header \libheader{cstdlib}: - -\begin{itemize} -\item -For a signed integer value, the function \tcode{strtoll}. -\item -For an unsigned integer value, the function \tcode{strtoull}. -\item -For a \tcode{float} value, the function \tcode{strtof}. -\item -For a \tcode{double} value, the function \tcode{strtod}. -\item -For a \tcode{long double} value, the function \tcode{strtold}. -\end{itemize} - -The numeric value to be stored can be one of: -\begin{itemize} -\item -zero, if the conversion function does not convert the entire field. -\item -the most positive (or negative) representable value, -if the field to be converted to a signed integer type represents a value -too large positive (or negative) to be represented in \tcode{val}. -\item -the most positive representable value, -if the field to be converted to an unsigned integer type represents a value -that cannot be represented in \tcode{val}. -\item -the converted value, otherwise. -\end{itemize} - -The resultant numeric value is stored in \tcode{val}. -If the conversion function does not convert the entire field, or -if the field represents a value outside the range of representable values, -\tcode{ios_base::failbit} is assigned to \tcode{err}. - -\end{description} - -\pnum -Digit grouping is checked. -That is, the positions of discarded -separators are examined for consistency with -\tcode{use_facet>(loc).grouping()}. -If they are not consistent -then \tcode{ios_base::failbit} is assigned to \tcode{err}. - -\pnum -In any case, -if stage 2 processing was terminated by the test for \tcode{in == end} -then \tcode{err |= ios_base::eofbit} is performed. -\end{itemdescr} - -\indexlibrarymember{do_get}{num_get}% -\begin{itemdecl} -iter_type do_get(iter_type in, iter_type end, ios_base& str, - ios_base::iostate& err, bool& val) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{(str.flags()\&ios_base::boolalpha) == 0} -then input proceeds as it would for a \tcode{long} -except that if a value is being stored into \tcode{val}, -the value is determined according to the following: -If the value to be stored is 0 then \tcode{false} is stored. -If the value is \tcode{1} then \tcode{true} is stored. -Otherwise \tcode{true} is stored and -\tcode{ios_base::failbit} is assigned to \tcode{err}. - -\pnum -Otherwise target sequences are determined ``as if'' by -calling the members \tcode{falsename()} and \tcode{truename()} of -the facet obtained by \tcode{use_facet>(str.getloc())}. -Successive characters in the range \range{in}{end} (see~\ref{sequence.reqmts}) -are obtained and matched against -corresponding positions in the target sequences -only as necessary to identify a unique match. -The input iterator \tcode{in} is compared to \tcode{end} -only when necessary to obtain a character. -If a target sequence is uniquely matched, -\tcode{val} is set to the corresponding value. -Otherwise \tcode{false} is stored and -\tcode{ios_base::failbit} is assigned to \tcode{err}. - -\pnum -The \tcode{in} iterator is always left pointing one position beyond -the last character successfully matched. -If \tcode{val} is set, then \tcode{err} is set to \tcode{str.goodbit}; -or to \tcode{str.eofbit} if, -when seeking another character to match, -it is found that \tcode{(in == end)}. -If \tcode{val} is not set, then \tcode{err} is set to \tcode{str.failbit}; -or to \tcode{(str.failbit|str.eofbit)} -if the reason for the failure was that \tcode{(in == end)}. -\begin{example} -For targets \tcode{true}: \tcode{"a"} and \tcode{false}: \tcode{"abb"}, -the input sequence \tcode{"a"} yields -\tcode{val == true} and \tcode{err == str.eofbit}; -the input sequence \tcode{"abc"} yields -\tcode{err = str.failbit}, with \tcode{in} ending at the \tcode{'c'} element. -For targets \tcode{true}: \tcode{"1"} and \tcode{false}: \tcode{"0"}, -the input sequence \tcode{"1"} yields -\tcode{val == true} and \tcode{err == str.goodbit}. -For empty targets \tcode{("")}, -any input sequence yields \tcode{err == str.failbit}. -\end{example} - -\pnum -\returns -\tcode{in}. -\end{itemdescr} - -\rSec3[locale.nm.put]{Class template \tcode{num_put}} - -\rSec4[locale.nm.put.general]{General} - -\indexlibraryglobal{num_put}% -\begin{codeblock} -namespace std { - template> - class num_put : public locale::facet { - public: - using char_type = charT; - using iter_type = OutputIterator; - - explicit num_put(size_t refs = 0); - - iter_type put(iter_type s, ios_base& f, char_type fill, bool v) const; - iter_type put(iter_type s, ios_base& f, char_type fill, long v) const; - iter_type put(iter_type s, ios_base& f, char_type fill, long long v) const; - iter_type put(iter_type s, ios_base& f, char_type fill, unsigned long v) const; - iter_type put(iter_type s, ios_base& f, char_type fill, unsigned long long v) const; - iter_type put(iter_type s, ios_base& f, char_type fill, double v) const; - iter_type put(iter_type s, ios_base& f, char_type fill, long double v) const; - iter_type put(iter_type s, ios_base& f, char_type fill, const void* v) const; - - static locale::id id; - - protected: - ~num_put(); - virtual iter_type do_put(iter_type, ios_base&, char_type fill, bool v) const; - virtual iter_type do_put(iter_type, ios_base&, char_type fill, long v) const; - virtual iter_type do_put(iter_type, ios_base&, char_type fill, long long v) const; - virtual iter_type do_put(iter_type, ios_base&, char_type fill, unsigned long) const; - virtual iter_type do_put(iter_type, ios_base&, char_type fill, unsigned long long) const; - virtual iter_type do_put(iter_type, ios_base&, char_type fill, double v) const; - virtual iter_type do_put(iter_type, ios_base&, char_type fill, long double v) const; - virtual iter_type do_put(iter_type, ios_base&, char_type fill, const void* v) const; - }; -} -\end{codeblock} - -\pnum -The facet -\tcode{num_put} -is used to format numeric values to a character sequence such as an ostream. - -\rSec4[facet.num.put.members]{Members} - -\indexlibrarymember{num_put}{put}% -\begin{itemdecl} -iter_type put(iter_type out, ios_base& str, char_type fill, bool val) const; -iter_type put(iter_type out, ios_base& str, char_type fill, long val) const; -iter_type put(iter_type out, ios_base& str, char_type fill, long long val) const; -iter_type put(iter_type out, ios_base& str, char_type fill, unsigned long val) const; -iter_type put(iter_type out, ios_base& str, char_type fill, unsigned long long val) const; -iter_type put(iter_type out, ios_base& str, char_type fill, double val) const; -iter_type put(iter_type out, ios_base& str, char_type fill, long double val) const; -iter_type put(iter_type out, ios_base& str, char_type fill, const void* val) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_put(out, str, fill, val)}. -\end{itemdescr} - -\rSec4[facet.num.put.virtuals]{Virtual functions} - -\indexlibrarymember{num_put}{do_put}% -\begin{itemdecl} -iter_type do_put(iter_type out, ios_base& str, char_type fill, long val) const; -iter_type do_put(iter_type out, ios_base& str, char_type fill, long long val) const; -iter_type do_put(iter_type out, ios_base& str, char_type fill, unsigned long val) const; -iter_type do_put(iter_type out, ios_base& str, char_type fill, unsigned long long val) const; -iter_type do_put(iter_type out, ios_base& str, char_type fill, double val) const; -iter_type do_put(iter_type out, ios_base& str, char_type fill, long double val) const; -iter_type do_put(iter_type out, ios_base& str, char_type fill, const void* val) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Writes characters to the sequence \tcode{out}, -formatting \tcode{val} as desired. -In the following description, \tcode{loc} names a local variable initialized as -\begin{codeblock} -locale loc = str.getloc(); -\end{codeblock} - -\pnum -The details of this operation occur in several stages: - -\begin{itemize} -\item -Stage 1: -Determine a printf conversion specifier \tcode{spec} and -determine the characters -that would be printed by \tcode{printf}\iref{c.files} -given this conversion specifier for -\begin{codeblock} -printf(spec, val) -\end{codeblock} -assuming that the current locale is the \tcode{"C"} locale. -\item -Stage 2: -Adjust the representation by converting -each \tcode{char} determined by stage 1 to a \tcode{charT} -using a conversion and -values returned by members of \tcode{use_facet>(loc)}. -\item -Stage 3: -Determine where padding is required. -\item -Stage 4: -Insert the sequence into the \tcode{out}. -\end{itemize} - -\pnum -Detailed descriptions of each stage follow. - -\pnum -\returns -\tcode{out}. - -\pnum -\begin{description} -\stage{1} -The first action of stage 1 is to determine a conversion specifier. -The tables that describe this determination use the following local variables - -\begin{codeblock} -fmtflags flags = str.flags(); -fmtflags basefield = (flags & (ios_base::basefield)); -fmtflags uppercase = (flags & (ios_base::uppercase)); -fmtflags floatfield = (flags & (ios_base::floatfield)); -fmtflags showpos = (flags & (ios_base::showpos)); -fmtflags showbase = (flags & (ios_base::showbase)); -fmtflags showpoint = (flags & (ios_base::showpoint)); -\end{codeblock} - -All tables used in describing stage 1 are ordered. -That is, the first line whose condition is true applies. -A line without a condition is the default behavior -when none of the earlier lines apply. - -For conversion from an integral type other than a character type, -the function determines the integral conversion specifier -as indicated in \tref{facet.num.put.int}. - -\begin{floattable}{Integer conversions}{facet.num.put.int} -{lc} -\topline -\lhdr{State} & \tcode{stdio} equivalent \\ \capsep -\tcode{basefield == ios_base::oct} & \tcode{\%o} \\ \rowsep -\tcode{(basefield == ios_base::hex) \&\& !uppercase} & \tcode{\%x} \\ \rowsep -\tcode{(basefield == ios_base::hex)} & \tcode{\%X} \\ \rowsep -for a \tcode{signed} integral type & \tcode{\%d} \\ \rowsep -for an \tcode{unsigned} integral type & \tcode{\%u} \\ -\end{floattable} - -For conversion from a floating-point type, -the function determines the floating-point conversion specifier -as indicated in \tref{facet.num.put.fp}. - -\begin{floattable}{Floating-point conversions}{facet.num.put.fp} -{lc} -\topline -\lhdr{State} & \tcode{stdio} equivalent \\ \capsep -\tcode{floatfield == ios_base::fixed} & \tcode{\%f} \\ \rowsep -\tcode{floatfield == ios_base::scientific \&\& !uppercase} & \tcode{\%e} \\ \rowsep -\tcode{floatfield == ios_base::scientific} & \tcode{\%E} \\ \rowsep -\tcode{floatfield == (ios_base::fixed | ios_base::scientific) \&\& !uppercase} & \tcode{\%a} \\ \rowsep -\tcode{floatfield == (ios_base::fixed | ios_base::scientific)} & \tcode{\%A} \\ \rowsep -\tcode{!uppercase} & \tcode{\%g} \\ \rowsep -\textit{otherwise} & \tcode{\%G} \\ -\end{floattable} - -For conversions from an integral or floating-point type -a length modifier is added to the conversion specifier -as indicated in \tref{facet.num.put.length}. - -\begin{floattable}{Length modifier}{facet.num.put.length} -{lc} -\topline -\lhdr{Type} & Length modifier \\ \capsep -\tcode{long} & \tcode{l} \\ \rowsep -\tcode{long long} & \tcode{ll} \\ \rowsep -\tcode{unsigned long} & \tcode{l} \\ \rowsep -\tcode{unsigned long long} & \tcode{ll} \\ \rowsep -\tcode{long double} & \tcode{L} \\ \rowsep -\textit{otherwise} & \textit{none} \\ -\end{floattable} - -The conversion specifier has the following optional additional qualifiers -prepended as indicated in \tref{facet.num.put.conv}. - -\begin{floattable}{Numeric conversions}{facet.num.put.conv} -{llc} -\topline -\lhdr{Type(s)} & \chdr{State} & \tcode{stdio} equivalent \\ \capsep -an integral type & \tcode{showpos} & \tcode{+} \\ - & \tcode{showbase} & \tcode{\#} \\ \rowsep -a floating-point type & \tcode{showpos} & \tcode{+} \\ - & \tcode{showpoint} & \tcode{\#} \\ -\end{floattable} - -For conversion from a floating-point type, -if \tcode{floatfield != (ios_base::fixed | ios_base::\brk{}scientific)}, -\tcode{str.precision()} is specified as precision -in the conversion specification. -Otherwise, no precision is specified. - -For conversion from \tcode{void*} the specifier is \tcode{\%p}. - -The representations at the end of stage 1 consists of the \tcode{char}'s -that would be printed by a call of \tcode{printf(s, val)} -where \tcode{s} is the conversion specifier determined above. - -\stage{2} -Any character \tcode{c} other than a decimal point(.) is converted to -a \tcode{charT} via -\begin{codeblock} -use_facet>(loc).widen(c) -\end{codeblock} - -A local variable \tcode{punct} is initialized via -\begin{codeblock} -const numpunct& punct = use_facet>(loc); -\end{codeblock} - -For arithmetic types, -\tcode{punct.thousands_sep()} characters are inserted into -the sequence as determined by the value returned by \tcode{punct.do_grouping()} -using the method described in~\ref{facet.numpunct.virtuals}. - -Decimal point characters(.) are replaced by \tcode{punct.decimal_point()}. - -\stage{3} -A local variable is initialized as -\begin{codeblock} -fmtflags adjustfield = (flags & (ios_base::adjustfield)); -\end{codeblock} - -The location of any padding -\begin{footnote} -The conversion specification \tcode{\#o} generates a leading \tcode{0} -which is \textit{not} a padding character. -\end{footnote} -is determined according to \tref{facet.num.put.fill}. - -\begin{floattable}{Fill padding}{facet.num.put.fill} -{p{3in}l} -\topline -\lhdr{State} & \rhdr{Location} \\ \capsep -\tcode{adjustfield == ios_base::left} & pad after \\ \rowsep -\tcode{adjustfield == ios_base::right} & pad before \\ \rowsep -\tcode{adjustfield == internal} and a sign occurs in the representation - & pad after the sign \\ \rowsep -\tcode{adjustfield == internal} and representation after stage 1 -began with 0x or 0X & pad after x or X \\ \rowsep -\textit{otherwise} & pad before \\ -\end{floattable} - -If \tcode{str.width()} is nonzero and the number of \tcode{charT}'s -in the sequence after stage 2 is less than \tcode{str.\brk{}width()}, -then enough \tcode{fill} characters are added to the sequence -at the position indicated for padding -to bring the length of the sequence to \tcode{str.width()}. - -\tcode{str.width(0)} is called. - -\stage{4} -The sequence of \tcode{charT}'s at the end of stage 3 are output via -\begin{codeblock} -*out++ = c -\end{codeblock} -\end{description} -\end{itemdescr} - -\indexlibrarymember{do_put}{num_put}% -\begin{itemdecl} -iter_type do_put(iter_type out, ios_base& str, char_type fill, bool val) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -If \tcode{(str.flags() \& ios_base::boolalpha) == 0} -returns \tcode{do_put(out, str, fill,\\(int)val)}, -otherwise obtains a string \tcode{s} as if by -\begin{codeblock} -string_type s = - val ? use_facet>(loc).truename() - : use_facet>(loc).falsename(); -\end{codeblock} -and then inserts each character \tcode{c} of \tcode{s} into \tcode{out} -via \tcode{*out++ = c} -and returns \tcode{out}. -\end{itemdescr} - -\rSec2[facet.numpunct]{The numeric punctuation facet} - -\rSec3[locale.numpunct]{Class template \tcode{numpunct}} - -\rSec4[locale.numpunct.general]{General} - -\indexlibraryglobal{numpunct}% -\begin{codeblock} -namespace std { - template - class numpunct : public locale::facet { - public: - using char_type = charT; - using string_type = basic_string; - - explicit numpunct(size_t refs = 0); - - char_type decimal_point() const; - char_type thousands_sep() const; - string grouping() const; - string_type truename() const; - string_type falsename() const; - - static locale::id id; - - protected: - ~numpunct(); // virtual - virtual char_type do_decimal_point() const; - virtual char_type do_thousands_sep() const; - virtual string do_grouping() const; - virtual string_type do_truename() const; // for \tcode{bool} - virtual string_type do_falsename() const; // for \tcode{bool} - }; -} -\end{codeblock} - -\pnum -\tcode{numpunct<>} specifies numeric punctuation. -The specializations -required in \tref{locale.category.facets}\iref{locale.category}, -namely \tcode{numpunct<\brk{}wchar_t>} and \tcode{numpunct}, -provide classic \tcode{"C"} numeric formats, -i.e., they contain information -equivalent to that contained in the \tcode{"C"} locale or -their wide character counterparts as if obtained by a call to \tcode{widen}. - -% FIXME: For now, keep the locale grammar productions out of the index; -% they are conceptually unrelated to the main C++ grammar. -% Consider renaming these en masse (to locale-* ?) to avoid this problem. -\newcommand{\locnontermdef}[1]{{\BnfNontermshape#1\itcorr}\textnormal{:}} -\newcommand{\locgrammarterm}[1]{\gterm{#1}} - -\pnum -The syntax for number formats is as follows, -where \locgrammarterm{digit} represents the radix set -specified by the \tcode{fmtflags} argument value, and -\locgrammarterm{thousands-sep} and \locgrammarterm{decimal-point} -are the results of corresponding \tcode{numpunct} members. -Integer values have the format: -\begin{ncbnf} -\locnontermdef{intval}\br - \opt{sign} units -\end{ncbnf} -\begin{ncbnf} -\locnontermdef{sign}\br - \terminal{+}\br - \terminal{-} -\end{ncbnf} -\begin{ncbnf} -\locnontermdef{units}\br - digits\br - digits thousands-sep units -\end{ncbnf} -\begin{ncbnf} -\locnontermdef{digits}\br - digit \opt{digits} -\end{ncbnf} -and floating-point values have: -\begin{ncbnf} -\locnontermdef{floatval}\br - \opt{sign} units \opt{fractional} \opt{exponent}\br - \opt{sign} decimal-point digits \opt{exponent} -\end{ncbnf} -\begin{ncbnf} -\locnontermdef{fractional}\br - decimal-point \opt{digits} -\end{ncbnf} -\begin{ncbnf} -\locnontermdef{exponent}\br - e \opt{sign} digits -\end{ncbnf} -\begin{ncbnf} -\locnontermdef{e}\br - \terminal{e}\br - \terminal{E} -\end{ncbnf} -where the number of digits between \locgrammarterm{thousands-sep}{s} -is as specified by \tcode{do_grouping()}. -For parsing, -if the \locgrammarterm{digits} portion contains no thousands-separators, -no grouping constraint is applied. - -\rSec4[facet.numpunct.members]{Members} - -\indexlibrarymember{numpunct}{decimal_point}% -\begin{itemdecl} -char_type decimal_point() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_decimal_point()}. -\end{itemdescr} - -\indexlibrarymember{numpunct}{thousands_sep}% -\begin{itemdecl} -char_type thousands_sep() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_thousands_sep()}. -\end{itemdescr} - -\indexlibrarymember{numpunct}{grouping}% -\begin{itemdecl} -string grouping() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_grouping()}. -\end{itemdescr} - -\indexlibrarymember{numpunct}{truename}% -\indexlibrarymember{numpunct}{falsename}% -\begin{itemdecl} -string_type truename() const; -string_type falsename() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_truename()} -or -\tcode{do_falsename()}, -respectively. -\end{itemdescr} - -\rSec4[facet.numpunct.virtuals]{Virtual functions} - -\indexlibrarymember{numpunct}{do_decimal_point}% -\begin{itemdecl} -char_type do_decimal_point() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A character for use as the decimal radix separator. -The required specializations return \tcode{'.'} or \tcode{L'.'}. -\end{itemdescr} - -\indexlibrarymember{numpunct}{do_thousands_sep}% -\begin{itemdecl} -char_type do_thousands_sep() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A character for use as the digit group separator. -The required specializations return \tcode{','} or \tcode{L','}. -\end{itemdescr} - -\indexlibrarymember{numpunct}{do_grouping}% -\begin{itemdecl} -string do_grouping() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A \tcode{string} \tcode{vec} used as a vector of integer values, -in which each element \tcode{vec[i]} represents the number of digits -\begin{footnote} -Thus, -the string \tcode{"\textbackslash003"} specifies groups of 3 digits each, and -\tcode{"3"} probably indicates groups of 51 (!) digits each, -because 51 is the ASCII value of \tcode{"3"}. -\end{footnote} -in the group at position \tcode{i}, -starting with position 0 as the rightmost group. -If \tcode{vec.size() <= i}, -the number is the same as group \tcode{(i - 1)}; -if \tcode{(i < 0 || vec[i] <= 0 || vec[i] == CHAR_MAX)}, -the size of the digit group is unlimited. - -\pnum -The required specializations return the empty string, indicating no grouping. -\end{itemdescr} - -\indexlibrarymember{numpunct}{do_truename}% -\indexlibrarymember{numpunct}{do_falsename}% -\begin{itemdecl} -string_type do_truename() const; -string_type do_falsename() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A string representing the name of -the boolean value \tcode{true} or \tcode{false}, respectively. - -\pnum -In the base class implementation -these names are \tcode{"true"} and \tcode{"false"}, -or \tcode{L"true"} and \tcode{L"false"}. -\end{itemdescr} - -\rSec3[locale.numpunct.byname]{Class template \tcode{numpunct_byname}} - -\indexlibraryglobal{numpunct_byname}% -\begin{codeblock} -namespace std { - template - class numpunct_byname : public numpunct { - // this class is specialized for \tcode{char} and \keyword{wchar_t}. - public: - using char_type = charT; - using string_type = basic_string; - - explicit numpunct_byname(const char*, size_t refs = 0); - explicit numpunct_byname(const string&, size_t refs = 0); - - protected: - ~numpunct_byname(); - }; -} -\end{codeblock} - -\rSec2[category.collate]{The collate category} - -\rSec3[locale.collate]{Class template \tcode{collate}} - -\rSec4[locale.collate.general]{General} - -\indexlibraryglobal{collate}% -\begin{codeblock} -namespace std { - template - class collate : public locale::facet { - public: - using char_type = charT; - using string_type = basic_string; - - explicit collate(size_t refs = 0); - - int compare(const charT* low1, const charT* high1, - const charT* low2, const charT* high2) const; - string_type transform(const charT* low, const charT* high) const; - long hash(const charT* low, const charT* high) const; - - static locale::id id; - - protected: - ~collate(); - virtual int do_compare(const charT* low1, const charT* high1, - const charT* low2, const charT* high2) const; - virtual string_type do_transform(const charT* low, const charT* high) const; - virtual long do_hash (const charT* low, const charT* high) const; - }; -} -\end{codeblock} - -\pnum -The class \tcode{collate} provides features -for use in the collation (comparison) and hashing of strings. -A locale member function template, \tcode{operator()}, -uses the collate facet to allow a locale to act directly as -the predicate argument for standard algorithms\iref{algorithms} and -containers operating on strings. -The specializations -required in \tref{locale.category.facets}\iref{locale.category}, -namely \tcode{collate} and \tcode{collate}, -apply lexicographical ordering\iref{alg.lex.comparison}. - -\pnum -Each function compares a string of characters \tcode{*p} -in the range \range{low}{high}. - -\rSec4[locale.collate.members]{Members} - -\indexlibrarymember{collate}{compare}% -\begin{itemdecl} -int compare(const charT* low1, const charT* high1, - const charT* low2, const charT* high2) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_compare(low1, high1, low2, high2)}. -\end{itemdescr} - -\indexlibrarymember{collate}{transform}% -\begin{itemdecl} -string_type transform(const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_transform(low, high)}. -\end{itemdescr} - -\indexlibrarymember{collate}{hash}% -\begin{itemdecl} -long hash(const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_hash(low, high)}. -\end{itemdescr} - -\rSec4[locale.collate.virtuals]{Virtual functions} - -\indexlibrarymember{collate}{do_compare}% -\begin{itemdecl} -int do_compare(const charT* low1, const charT* high1, - const charT* low2, const charT* high2) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{1} if the first string is greater than the second, -\tcode{-1} if less, -zero otherwise. -The specializations -required in \tref{locale.category.facets}\iref{locale.category}, -namely \tcode{collate} and \tcode{collate}, -implement a lexicographical comparison\iref{alg.lex.comparison}. -\end{itemdescr} - -\indexlibrarymember{collate}{do_transform}% -\begin{itemdecl} -string_type do_transform(const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A \tcode{basic_string} value that, -compared lexicographically with -the result of calling \tcode{transform()} on another string, -yields the same result as calling \tcode{do_compare()} on the same two strings. -\begin{footnote} -This function is useful when one string is being compared to many other strings. -\end{footnote} -\end{itemdescr} - -\indexlibrarymember{collate}{do_hash}% -\begin{itemdecl} -long do_hash(const charT* low, const charT* high) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -An integer value equal to the result of calling \tcode{hash()} -on any other string for which \tcode{do_compare()} returns 0 (equal) -when passed the two strings. - -\pnum -\recommended -The probability that the result equals that for another string -which does not compare equal should be very small, -approaching \tcode{(1.0/numeric_limits::max())}. -\end{itemdescr} - -\rSec3[locale.collate.byname]{Class template \tcode{collate_byname}} - -\indexlibraryglobal{collate_byname}% -\begin{codeblock} -namespace std { - template - class collate_byname : public collate { - public: - using string_type = basic_string; - - explicit collate_byname(const char*, size_t refs = 0); - explicit collate_byname(const string&, size_t refs = 0); - - protected: - ~collate_byname(); - }; -} -\end{codeblock} - -\rSec2[category.time]{The time category} - -\rSec3[category.time.general]{General} - -\pnum -Templates -\tcode{time_get} and -\tcode{time_put} -provide date and time formatting and parsing. -All specifications of member functions for \tcode{time_put} and \tcode{time_get} -in the subclauses of~\ref{category.time} only apply to the -specializations required in Tables~\ref{tab:locale.category.facets} -and~\ref{tab:locale.spec}\iref{locale.category}. -Their members use their -\tcode{ios_base\&}, \tcode{ios_base::iostate\&}, and \tcode{fill} arguments -as described in~\ref{locale.categories}, -and the \tcode{ctype<>} facet, -to determine formatting details. - -\rSec3[locale.time.get]{Class template \tcode{time_get}} - -\rSec4[locale.time.get.general]{General} - -\indexlibraryglobal{time_get}% -\begin{codeblock} -namespace std { - class time_base { - public: - enum dateorder { no_order, dmy, mdy, ymd, ydm }; - }; - - template> - class time_get : public locale::facet, public time_base { - public: - using char_type = charT; - using iter_type = InputIterator; - - explicit time_get(size_t refs = 0); - - dateorder date_order() const { return do_date_order(); } - iter_type get_time(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t) const; - iter_type get_date(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t) const; - iter_type get_weekday(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t) const; - iter_type get_monthname(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t) const; - iter_type get_year(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t) const; - iter_type get(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t, char format, char modifier = 0) const; - iter_type get(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t, const char_type* fmt, - const char_type* fmtend) const; - - static locale::id id; - - protected: - ~time_get(); - virtual dateorder do_date_order() const; - virtual iter_type do_get_time(iter_type s, iter_type end, ios_base&, - ios_base::iostate& err, tm* t) const; - virtual iter_type do_get_date(iter_type s, iter_type end, ios_base&, - ios_base::iostate& err, tm* t) const; - virtual iter_type do_get_weekday(iter_type s, iter_type end, ios_base&, - ios_base::iostate& err, tm* t) const; - virtual iter_type do_get_monthname(iter_type s, iter_type end, ios_base&, - ios_base::iostate& err, tm* t) const; - virtual iter_type do_get_year(iter_type s, iter_type end, ios_base&, - ios_base::iostate& err, tm* t) const; - virtual iter_type do_get(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t, char format, char modifier) const; - }; -} -\end{codeblock} - -\pnum -\tcode{time_get} is used to parse a character sequence, -extracting components of a time or date into a \tcode{tm} object. -Each \tcode{get} member parses a format as produced by a corresponding format specifier to -\tcode{time_put<>::put}. -If the sequence being parsed matches the correct format, the corresponding -members of the -\tcode{tm} -argument are set to the values used to produce the sequence; otherwise -either an error is reported or unspecified values are assigned. -\begin{footnote} -In -other words, user confirmation is required for reliable parsing of -user-entered dates and times, but machine-generated formats can be -parsed reliably. -This allows parsers to be aggressive about -interpreting user variations on standard formats. -\end{footnote} - -\pnum -If the end iterator is reached during parsing by any of the -\tcode{get()} -member functions, the member sets -\tcode{ios_base::eof\-bit} -in \tcode{err}. - -\rSec4[locale.time.get.members]{Members} - -\indexlibrarymember{time_get}{date_order}% -\begin{itemdecl} -dateorder date_order() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_date_order()}. -\end{itemdescr} - -\indexlibrarymember{time_get}{get_time}% -\begin{itemdecl} -iter_type get_time(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get_time(s, end, str, err, t)}. -\end{itemdescr} - -\indexlibrarymember{time_get}{get_date}% -\begin{itemdecl} -iter_type get_date(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get_date(s, end, str, err, t)}. -\end{itemdescr} - -\indexlibrarymember{time_get}{get_weekday}% -\indexlibrarymember{time_get}{get_monthname}% -\begin{itemdecl} -iter_type get_weekday(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -iter_type get_monthname(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get_weekday(s, end, str, err, t)} -or -\tcode{do_get_monthname(s, end, str, err, t)}. -\end{itemdescr} - -\indexlibrarymember{time_get}{get_year}% -\begin{itemdecl} -iter_type get_year(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get_year(s, end, str, err, t)}. -\end{itemdescr} - -\indexlibrarymember{get}{time_get}% -\begin{itemdecl} -iter_type get(iter_type s, iter_type end, ios_base& f, ios_base::iostate& err, - tm* t, char format, char modifier = 0) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get(s, end, f, err, t, format, modifier)}. -\end{itemdescr} - -\indexlibrarymember{get}{time_get}% -\begin{itemdecl} -iter_type get(iter_type s, iter_type end, ios_base& f, ios_base::iostate& err, - tm* t, const char_type* fmt, const char_type* fmtend) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\range{fmt}{fmtend} is a valid range. - -\pnum -\effects -The function starts by evaluating \tcode{err = ios_base::goodbit}. -It then enters a loop, -reading zero or more characters from \tcode{s} at each iteration. -Unless otherwise specified below, -the loop terminates when the first of the following conditions holds: - -\begin{itemize} -\item -The expression \tcode{fmt == fmtend} evaluates to \tcode{true}. -\item -The expression \tcode{err == ios_base::goodbit} evaluates to \tcode{false}. -\item -The expression \tcode{s == end} evaluates to \tcode{true}, -in which case -the function evaluates \tcode{err = ios_base::eofbit | ios_base::failbit}. -\item -The next element of \tcode{fmt} is equal to \tcode{'\%'}, -optionally followed by a modifier character, -followed by a conversion specifier character, \tcode{format}, -together forming a conversion specification -valid for the POSIX function \tcode{strptime}. -If the number of elements in the range \range{fmt}{fmtend} -is not sufficient to unambiguously determine -whether the conversion specification is complete and valid, -the function evaluates \tcode{err = ios_base::failbit}. -Otherwise, -the function evaluates \tcode{s = do_get(s, end, f, err, t, format, modifier)}, -where the value of \tcode{modifier} is \tcode{'\textbackslash0'} -when the optional modifier is absent from the conversion specification. -If \tcode{err == ios_base::goodbit} holds -after the evaluation of the expression, -the function increments \tcode{fmt} -to point just past the end of the conversion specification and -continues looping. - -\item -The expression \tcode{isspace(*fmt, f.getloc())} evaluates to \tcode{true}, -in which case the function first increments \tcode{fmt} until -\tcode{fmt == fmtend || !isspace(*fmt, f.getloc())} evaluates to \tcode{true}, -then advances \tcode{s} -until \tcode{s == end || !isspace(*s, f.getloc())} is \tcode{true}, and -finally resumes looping. - -\item -The next character read from \tcode{s} -matches the element pointed to by \tcode{fmt} in a case-insensitive comparison, -in which case the function evaluates \tcode{++fmt, ++s} and continues looping. -Otherwise, the function evaluates \tcode{err = ios_base::failbit}. -\end{itemize} - -\pnum -\begin{note} -The function uses the \tcode{ctype} facet -installed in \tcode{f}'s locale -to determine valid whitespace characters. -It is unspecified -by what means the function performs case-insensitive comparison or -whether multi-character sequences are considered while doing so. -\end{note} - -\pnum -\returns -\tcode{s}. -\end{itemdescr} - -\rSec4[locale.time.get.virtuals]{Virtual functions} - -\indexlibrarymember{time_get}{do_date_order}% -\begin{itemdecl} -dateorder do_date_order() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -An enumeration value indicating the preferred order of components -for those date formats that are composed of day, month, and year. -\begin{footnote} -This function is intended as a convenience only, for common formats, and -can return \tcode{no_order} in valid locales. -\end{footnote} -Returns \tcode{no_order} if the date format specified by \tcode{'x'} -contains other variable components (e.g., Julian day, week number, week day). -\end{itemdescr} - -\indexlibrarymember{time_get}{do_get_time}% -\begin{itemdecl} -iter_type do_get_time(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Reads characters starting at \tcode{s} -until it has extracted those \tcode{tm} members, and -remaining format characters, -used by \tcode{time_put<>::put} -to produce the format specified by \tcode{"\%H:\%M:\%S"}, -or until it encounters an error or end of sequence. - -\pnum -\returns -An iterator pointing immediately beyond -the last character recognized as possibly part of a valid time. -\end{itemdescr} - -\indexlibrarymember{time_get}{do_get_date}% -\begin{itemdecl} -iter_type do_get_date(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Reads characters starting at \tcode{s} -until it has extracted those \tcode{tm} members and -remaining format characters -used by \tcode{time_put<>::put} -to produce one of the following formats, -or until it encounters an error. -The format depends on the value returned by \tcode{date_order()} -as shown in \tref{locale.time.get.dogetdate}. - -\begin{libtab2}{\tcode{do_get_date} effects}{locale.time.get.dogetdate} -{ll}{\tcode{date_order()}}{Format} -\tcode{no_order} & \tcode{"\%m\%d\%y"} \\ -\tcode{dmy} & \tcode{"\%d\%m\%y"} \\ -\tcode{mdy} & \tcode{"\%m\%d\%y"} \\ -\tcode{ymd} & \tcode{"\%y\%m\%d"} \\ -\tcode{ydm} & \tcode{"\%y\%d\%m"} \\ -\end{libtab2} - -\pnum -An implementation may also accept additional -\impldef{additional formats for \tcode{time_get::do_get_date}} formats. - -\pnum -\returns -An iterator pointing immediately beyond -the last character recognized as possibly part of a valid date. -\end{itemdescr} - -\indexlibrarymember{time_get}{do_get_weekday}% -\indexlibrarymember{time_get}{do_get_monthname}% -\begin{itemdecl} -iter_type do_get_weekday(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -iter_type do_get_monthname(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Reads characters starting at \tcode{s} -until it has extracted the (perhaps abbreviated) name of a weekday or month. -If it finds an abbreviation -that is followed by characters that can match a full name, -it continues reading until it matches the full name or fails. -It sets the appropriate \tcode{tm} member accordingly. - -\pnum -\returns -An iterator pointing immediately beyond the last character recognized -as part of a valid name. -\end{itemdescr} - -\indexlibrarymember{time_get}{do_get_year}% -\begin{itemdecl} -iter_type do_get_year(iter_type s, iter_type end, ios_base& str, - ios_base::iostate& err, tm* t) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Reads characters starting at \tcode{s} -until it has extracted an unambiguous year identifier. -It is -\impldef{whether \tcode{time_get::do_get_year} accepts two-digit year numbers} -whether two-digit year numbers are accepted, -and (if so) what century they are assumed to lie in. -Sets the \tcode{t->tm_year} member accordingly. - -\pnum -\returns -An iterator pointing immediately beyond -the last character recognized as part of a valid year identifier. -\end{itemdescr} - -\indexlibrarymember{do_get}{time_get}% -\begin{itemdecl} -iter_type do_get(iter_type s, iter_type end, ios_base& f, - ios_base::iostate& err, tm* t, char format, char modifier) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{t} points to an object. - -\pnum -\effects -The function starts by evaluating \tcode{err = ios_base::goodbit}. -It then reads characters starting at \tcode{s} until it encounters an error, or -until it has extracted and assigned those \tcode{tm} members, and -any remaining format characters, -corresponding to a conversion specification appropriate for -the POSIX function \tcode{strptime}, -formed by concatenating \tcode{'\%'}, -the \tcode{modifier} character, when non-NUL, and -the \tcode{format} character. -When the concatenation fails to yield a complete valid directive -the function leaves the object pointed to by \tcode{t} unchanged and -evaluates \tcode{err |= ios_base::failbit}. -When \tcode{s == end} evaluates to \tcode{true} after reading a character -the function evaluates \tcode{err |= ios_base::eofbit}. - -\pnum -For complex conversion specifications -such as \tcode{\%c}, \tcode{\%x}, or \tcode{\%X}, or -conversion specifications that involve the optional modifiers \tcode{E} or \tcode{O}, -when the function is unable to unambiguously determine -some or all \tcode{tm} members from the input sequence \range{s}{end}, -it evaluates \tcode{err |= ios_base::eofbit}. -In such cases the values of those \tcode{tm} members are unspecified -and may be outside their valid range. - -\pnum -\returns -An iterator pointing immediately beyond -the last character recognized as possibly part of -a valid input sequence for the given \tcode{format} and \tcode{modifier}. - -\pnum -\remarks -It is unspecified whether multiple calls to \tcode{do_get()} -with the address of the same \tcode{tm} object -will update the current contents of the object or simply overwrite its members. -Portable programs should zero out the object before invoking the function. -\end{itemdescr} - -\rSec3[locale.time.get.byname]{Class template \tcode{time_get_byname}} - -\indexlibraryglobal{time_get_byname}% -\begin{codeblock} -namespace std { - template> - class time_get_byname : public time_get { - public: - using dateorder = time_base::dateorder; - using iter_type = InputIterator; - - explicit time_get_byname(const char*, size_t refs = 0); - explicit time_get_byname(const string&, size_t refs = 0); - - protected: - ~time_get_byname(); - }; -} -\end{codeblock} - -\rSec3[locale.time.put]{Class template \tcode{time_put}} - -\indexlibraryglobal{time_put}% -\begin{codeblock} -namespace std { - template> - class time_put : public locale::facet { - public: - using char_type = charT; - using iter_type = OutputIterator; - - explicit time_put(size_t refs = 0); - - // the following is implemented in terms of other member functions. - iter_type put(iter_type s, ios_base& f, char_type fill, const tm* tmb, - const charT* pattern, const charT* pat_end) const; - iter_type put(iter_type s, ios_base& f, char_type fill, - const tm* tmb, char format, char modifier = 0) const; - - static locale::id id; - - protected: - ~time_put(); - virtual iter_type do_put(iter_type s, ios_base&, char_type, const tm* t, - char format, char modifier) const; - }; -} -\end{codeblock} - -\rSec4[locale.time.put.members]{Members} - -\indexlibrarymember{time_put}{put}% -\begin{itemdecl} -iter_type put(iter_type s, ios_base& str, char_type fill, const tm* t, - const charT* pattern, const charT* pat_end) const; -iter_type put(iter_type s, ios_base& str, char_type fill, const tm* t, - char format, char modifier = 0) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -The first form steps through the sequence -from \tcode{pattern} to \tcode{pat_end}, -identifying characters that are part of a format sequence. -Each character that is not part of a format sequence -is written to \tcode{s} immediately, and -each format sequence, as it is identified, results in a call to \tcode{do_put}; -thus, format elements and other characters are interleaved in the output -in the order in which they appear in the pattern. -Format sequences are identified by converting each character \tcode{c} to -a \tcode{char} value as if by \tcode{ct.narrow(c, 0)}, -where \tcode{ct} is a reference to \tcode{ctype} -obtained from \tcode{str.getloc()}. -The first character of each sequence is equal to \tcode{'\%'}, -followed by an optional modifier character \tcode{mod} -\begin{footnote} -Although the C programming language defines no modifiers, most vendors do. -\end{footnote} -and a format specifier character \tcode{spec} -as defined for the function \tcode{strftime}. -If no modifier character is present, \tcode{mod} is zero. -For each valid format sequence identified, -calls \tcode{do_put(s, str, fill, t, spec, mod)}. - -\pnum -The second form calls \tcode{do_put(s, str, fill, t, format, modifier)}. - -\pnum -\begin{note} -The \tcode{fill} argument can be used -in the implementation-defined formats or by derivations. -A space character is a reasonable default for this argument. -\end{note} - -\pnum -\returns -An iterator pointing immediately after the last character produced. -\end{itemdescr} - -\rSec4[locale.time.put.virtuals]{Virtual functions} - -\indexlibrarymember{time_put}{do_put}% -\begin{itemdecl} -iter_type do_put(iter_type s, ios_base&, char_type fill, const tm* t, - char format, char modifier) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Formats the contents of the parameter \tcode{t} -into characters placed on the output sequence \tcode{s}. -Formatting is controlled by the parameters \tcode{format} and \tcode{modifier}, -interpreted identically as the format specifiers -in the string argument to the standard library function -\indexlibraryglobal{strftime}% -\tcode{strftime()}, -except that the sequence of characters produced for those specifiers -that are described as depending on the C locale -are instead -\impldef{formatted character sequence generated by \tcode{time_put::do_put} -in C locale}. -\begin{note} -Interpretation of the \tcode{modifier} argument is implementation-defined. -\end{note} - -\pnum -\returns -An iterator pointing immediately after the last character produced. -\begin{note} -The \tcode{fill} argument can be used -in the implementation-defined formats or by derivations. -A space character is a reasonable default for this argument. -\end{note} - -\pnum -\recommended -Interpretation of the \tcode{modifier} should follow POSIX conventions. -Implementations should refer to other standards such as POSIX -for a specification of the character sequences produced for -those specifiers described as depending on the C locale. -\end{itemdescr} - -\rSec3[locale.time.put.byname]{Class template \tcode{time_put_byname}} - -\indexlibraryglobal{time_put_byname}% -\begin{codeblock} -namespace std { - template> - class time_put_byname : public time_put { - public: - using char_type = charT; - using iter_type = OutputIterator; - - explicit time_put_byname(const char*, size_t refs = 0); - explicit time_put_byname(const string&, size_t refs = 0); - - protected: - ~time_put_byname(); - }; -} -\end{codeblock} - -\rSec2[category.monetary]{The monetary category} - -\rSec3[category.monetary.general]{General} - -\pnum -These templates handle monetary formats. -A template parameter indicates -whether local or international monetary formats are to be used. - -\pnum -All specifications of member functions -for \tcode{money_put} and \tcode{money_get} -in the subclauses of~\ref{category.monetary} only apply to -the specializations required in Tables~\ref{tab:locale.category.facets} -and~\ref{tab:locale.spec}\iref{locale.category}. -Their members use their \tcode{ios_base\&}, \tcode{ios_base::io\-state\&}, -and \tcode{fill} arguments as described in~\ref{locale.categories}, and -the \tcode{moneypunct<>} and \tcode{ctype<>} facets, -to determine formatting details. - -\rSec3[locale.money.get]{Class template \tcode{money_get}} - -\indexlibraryglobal{money_get}% -\begin{codeblock} -namespace std { - template> - class money_get : public locale::facet { - public: - using char_type = charT; - using iter_type = InputIterator; - using string_type = basic_string; - - explicit money_get(size_t refs = 0); - - iter_type get(iter_type s, iter_type end, bool intl, - ios_base& f, ios_base::iostate& err, - long double& units) const; - iter_type get(iter_type s, iter_type end, bool intl, - ios_base& f, ios_base::iostate& err, - string_type& digits) const; - - static locale::id id; - - protected: - ~money_get(); - virtual iter_type do_get(iter_type, iter_type, bool, ios_base&, - ios_base::iostate& err, long double& units) const; - virtual iter_type do_get(iter_type, iter_type, bool, ios_base&, - ios_base::iostate& err, string_type& digits) const; - }; -} -\end{codeblock} - -\rSec4[locale.money.get.members]{Members} - -\indexlibrarymember{money_get}{get}% -\begin{itemdecl} -iter_type get(iter_type s, iter_type end, bool intl, ios_base& f, - ios_base::iostate& err, long double& quant) const; -iter_type get(iter_type s, iter_type end, bool intl, ios_base& f, - ios_base::iostate& err, string_type& quant) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get(s, end, intl, f, err, quant)}. -\end{itemdescr} - -\rSec4[locale.money.get.virtuals]{Virtual functions} - -\indexlibrarymember{money_get}{do_get}% -\begin{itemdecl} -iter_type do_get(iter_type s, iter_type end, bool intl, ios_base& str, - ios_base::iostate& err, long double& units) const; -iter_type do_get(iter_type s, iter_type end, bool intl, ios_base& str, - ios_base::iostate& err, string_type& digits) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Reads characters from \tcode{s} to parse and construct a monetary value -according to the format specified by -a \tcode{moneypunct} facet reference \tcode{mp} -and the character mapping specified by -a \tcode{ctype} facet reference \tcode{ct} -obtained from the locale returned by \tcode{str.getloc()}, and -\tcode{str.flags()}. -If a valid sequence is recognized, does not change \tcode{err}; -otherwise, sets \tcode{err} to \tcode{(err|str.failbit)}, or -\tcode{(err|str.failbit|str.eof\-bit)} if no more characters are available, -and does not change \tcode{units} or \tcode{digits}. -Uses the pattern returned by \tcode{mp.neg_format()} to parse all values. -The result is returned as an integral value stored in \tcode{units} -or as a sequence of digits possibly preceded by a minus sign -(as produced by \tcode{ct.widen(c)} -where \tcode{c} is \tcode{'-'} or -in the range from \tcode{'0'} through \tcode{'9'} (inclusive)) -stored in \tcode{digits}. -\begin{example} -The sequence \tcode{\$1,056.23} in a common United States locale would yield, -for \tcode{units}, \tcode{105623}, or, -for \tcode{digits}, \tcode{"105623"}. -\end{example} -If \tcode{mp.grouping()} indicates that no thousands separators are permitted, -any such characters are not read, and -parsing is terminated at the point where they first appear. -Otherwise, thousands separators are optional; -if present, they are checked for correct placement only after -all format components have been read. - -\pnum -Where \tcode{money_base::space} or \tcode{money_base::none} -appears as the last element in the format pattern, -no whitespace is consumed. -Otherwise, where \tcode{money_base::space} appears in any of -the initial elements of the format pattern, -at least one whitespace character is required. -Where \tcode{money_base::none} appears -in any of the initial elements of the format pattern, -whitespace is allowed but not required. -If \tcode{(str.flags() \& str.showbase)} is \tcode{false}, -the currency symbol is optional and -is consumed only if other characters are needed to complete the format; -otherwise, the currency symbol is required. - -\pnum -If the first character (if any) in -the string \tcode{pos} returned by \tcode{mp.positive_sign()} or -the string \tcode{neg} returned by \tcode{mp.negative_sign()} -is recognized in the position indicated by \tcode{sign} in the format pattern, -it is consumed and -any remaining characters in the string are required -after all the other format components. -\begin{example} -If \tcode{showbase} is off, -then for a \tcode{neg} value of \tcode{"()"} and -a currency symbol of \tcode{"L"}, -in \tcode{"(100 L)"} the \tcode{"L"} is consumed; -but if \tcode{neg} is \tcode{"-"}, -the \tcode{"L"} in \tcode{"-100 L"} is not consumed. -\end{example} -If \tcode{pos} or \tcode{neg} is empty, -the sign component is optional, and -if no sign is detected, -the result is given the sign that corresponds to the source of the empty string. -Otherwise, -the character in the indicated position must match -the first character of \tcode{pos} or \tcode{neg}, -and the result is given the corresponding sign. -If the first character of \tcode{pos} is equal to -the first character of \tcode{neg}, -or if both strings are empty, -the result is given a positive sign. - -\pnum -Digits in the numeric monetary component are extracted and -placed in \tcode{digits}, or into a character buffer \tcode{buf1} -for conversion to produce a value for \tcode{units}, -in the order in which they appear, -preceded by a minus sign if and only if the result is negative. -The value \tcode{units} is produced as if by -\begin{footnote} -The semantics here are different from \tcode{ct.narrow}. -\end{footnote} -\begin{codeblock} -for (int i = 0; i < n; ++i) - buf2[i] = src[find(atoms, atoms+sizeof(src), buf1[i]) - atoms]; -buf2[n] = 0; -sscanf(buf2, "%Lf", &units); -\end{codeblock} -where \tcode{n} is the number of characters placed in \tcode{buf1}, -\tcode{buf2} is a character buffer, and -the values \tcode{src} and \tcode{atoms} are defined as if by -\begin{codeblock} -static const char src[] = "0123456789-"; -charT atoms[sizeof(src)]; -ct.widen(src, src + sizeof(src) - 1, atoms); -\end{codeblock} - -\pnum -\returns -An iterator pointing immediately beyond -the last character recognized as part of a valid monetary quantity. -\end{itemdescr} - -\rSec3[locale.money.put]{Class template \tcode{money_put}} - -\indexlibraryglobal{money_put}% -\begin{codeblock} -namespace std { - template> - class money_put : public locale::facet { - public: - using char_type = charT; - using iter_type = OutputIterator; - using string_type = basic_string; - - explicit money_put(size_t refs = 0); - - iter_type put(iter_type s, bool intl, ios_base& f, - char_type fill, long double units) const; - iter_type put(iter_type s, bool intl, ios_base& f, - char_type fill, const string_type& digits) const; - - static locale::id id; - - protected: - ~money_put(); - virtual iter_type do_put(iter_type, bool, ios_base&, char_type fill, - long double units) const; - virtual iter_type do_put(iter_type, bool, ios_base&, char_type fill, - const string_type& digits) const; - }; -} -\end{codeblock} - -\rSec4[locale.money.put.members]{Members} - -\indexlibrarymember{money_put}{put}% -\begin{itemdecl} -iter_type put(iter_type s, bool intl, ios_base& f, char_type fill, long double quant) const; -iter_type put(iter_type s, bool intl, ios_base& f, char_type fill, const string_type& quant) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_put(s, intl, f, loc, quant)}. -\end{itemdescr} - -\rSec4[locale.money.put.virtuals]{Virtual functions} - -\indexlibrarymember{money_put}{do_put}% -\begin{itemdecl} -iter_type do_put(iter_type s, bool intl, ios_base& str, - char_type fill, long double units) const; -iter_type do_put(iter_type s, bool intl, ios_base& str, - char_type fill, const string_type& digits) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Writes characters to \tcode{s} according to -the format specified by -a \tcode{moneypunct} facet reference \tcode{mp} and -the character mapping specified by -a \tcode{ctype} facet reference \tcode{ct} -obtained from the locale returned by \tcode{str.getloc()}, -and \tcode{str.flags()}. -The argument \tcode{units} is transformed into -a sequence of wide characters as if by -\begin{codeblock} -ct.widen(buf1, buf1 + sprintf(buf1, "%.0Lf", units), buf2) -\end{codeblock} -for character buffers \tcode{buf1} and \tcode{buf2}. -If the first character in \tcode{digits} or \tcode{buf2} -is equal to \tcode{ct.widen('-')}, -then the pattern used for formatting is the result of \tcode{mp.neg_format()}; -otherwise the pattern is the result of \tcode{mp.pos_format()}. -Digit characters are written, -interspersed with any thousands separators and decimal point -specified by the format, -in the order they appear (after the optional leading minus sign) in -\tcode{digits} or \tcode{buf2}. -In \tcode{digits}, -only the optional leading minus sign and -the immediately subsequent digit characters -(as classified according to \tcode{ct}) -are used; -any trailing characters -(including digits appearing after a non-digit character) -are ignored. -Calls \tcode{str.width(0)}. - -\pnum -\returns -An iterator pointing immediately after the last character produced. - -\pnum -\remarks -% issues 22-021, 22-030, 22-034 from 97-0058/N1096, 97-0036/N1074 -The currency symbol is generated -if and only if \tcode{(str.flags() \& str.showbase)} is nonzero. -If the number of characters generated for the specified format -is less than the value returned by \tcode{str.width()} on entry to the function, -then copies of \tcode{fill} are inserted as necessary -to pad to the specified width. -For the value \tcode{af} equal to \tcode{(str.flags() \& str.adjustfield)}, -if \tcode{(af == str.internal)} is \tcode{true}, -the fill characters are placed -where \tcode{none} or \tcode{space} appears in the formatting pattern; -otherwise if \tcode{(af == str.left)} is \tcode{true}, -they are placed after the other characters; -otherwise, they are placed before the other characters. -\begin{note} -It is possible, with some combinations of format patterns and flag values, -to produce output that cannot be parsed using \tcode{num_get<>::get}. -\end{note} -\end{itemdescr} - -\rSec3[locale.moneypunct]{Class template \tcode{moneypunct}} - -\rSec4[locale.moneypunct.general]{General} - -\indexlibraryglobal{moneypunct}% -\begin{codeblock} -namespace std { - class money_base { - public: - enum part { none, space, symbol, sign, value }; - struct pattern { char field[4]; }; - }; - - template - class moneypunct : public locale::facet, public money_base { - public: - using char_type = charT; - using string_type = basic_string; - - explicit moneypunct(size_t refs = 0); - - charT decimal_point() const; - charT thousands_sep() const; - string grouping() const; - string_type curr_symbol() const; - string_type positive_sign() const; - string_type negative_sign() const; - int frac_digits() const; - pattern pos_format() const; - pattern neg_format() const; - - static locale::id id; - static const bool intl = International; - - protected: - ~moneypunct(); - virtual charT do_decimal_point() const; - virtual charT do_thousands_sep() const; - virtual string do_grouping() const; - virtual string_type do_curr_symbol() const; - virtual string_type do_positive_sign() const; - virtual string_type do_negative_sign() const; - virtual int do_frac_digits() const; - virtual pattern do_pos_format() const; - virtual pattern do_neg_format() const; - }; -} -\end{codeblock} - -\pnum -The \tcode{moneypunct<>} facet defines monetary formatting parameters -used by \tcode{money_get<>} and \tcode{money_put<>}. -A monetary format is a sequence of four components, -specified by a \tcode{pattern} value \tcode{p}, -such that the \tcode{part} value \tcode{static_cast(p.field[i])} -determines the $\tcode{i}^\text{th}$ component of the format -\begin{footnote} -An array of \tcode{char}, -rather than an array of \tcode{part}, -is specified for \tcode{pattern::field} purely for efficiency. -\end{footnote} -In the \tcode{field} member of a \tcode{pattern} object, -each value \tcode{symbol}, \tcode{sign}, \tcode{value}, and -either \tcode{space} or \tcode{none} -appears exactly once. -The value \tcode{none}, if present, is not first; -the value \tcode{space}, if present, is neither first nor last. - -\pnum -Where \tcode{none} or \tcode{space} appears, -whitespace is permitted in the format, -except where \tcode{none} appears at the end, -in which case no whitespace is permitted. -The value \tcode{space} indicates that -at least one space is required at that position. -Where \tcode{symbol} appears, -the sequence of characters returned by \tcode{curr_symbol()} is permitted, and -can be required. -Where \tcode{sign} appears, -the first (if any) of the sequence of characters returned by -\tcode{positive_sign()} or \tcode{negative_sign()} -(respectively as the monetary value is non-negative or negative) is required. -Any remaining characters of the sign sequence are required after -all other format components. -Where \tcode{value} appears, the absolute numeric monetary value is required. - -\pnum -The format of the numeric monetary value is a decimal number: -\begin{ncbnf} -\locnontermdef{value}\br - units \opt{fractional}\br - decimal-point digits -\end{ncbnf} -\begin{ncbnf} -\locnontermdef{fractional}\br - decimal-point \opt{digits} -\end{ncbnf} -if \tcode{frac_digits()} returns a positive value, or -\begin{ncbnf} -\locnontermdef{value}\br - units -\end{ncbnf} -otherwise. -The symbol \locgrammarterm{decimal-point} -indicates the character returned by \tcode{decimal_point()}. -The other symbols are defined as follows: - -\begin{ncbnf} -\locnontermdef{units}\br - digits\br - digits thousands-sep units -\end{ncbnf} - -\begin{ncbnf} -\locnontermdef{digits}\br - adigit \opt{digits} -\end{ncbnf} - -In the syntax specification, -the symbol \locgrammarterm{adigit} is any of the values \tcode{ct.widen(c)} -for \tcode{c} in the range \tcode{'0'} through \tcode{'9'} (inclusive) and -\tcode{ct} is a reference of type \tcode{const ctype\&} -obtained as described in the definitions -of \tcode{money_get<>} and \tcode{money_put<>}. -The symbol \locgrammarterm{thousands-sep} -is the character returned by \tcode{thousands_sep()}. -The space character used is the value \tcode{ct.widen(' ')}. -Whitespace characters are those characters \tcode{c} -for which \tcode{ci.is(space, c)} returns \tcode{true}. -The number of digits required after the decimal point (if any) -is exactly the value returned by \tcode{frac_digits()}. - -\pnum -The placement of thousands-separator characters (if any) -is determined by the value returned by \tcode{grouping()}, -defined identically as the member \tcode{numpunct<>::do_grouping()}. - -\rSec4[locale.moneypunct.members]{Members} - -\indexlibrarymember{moneypunct}{decimal_point}% -\indexlibrarymember{moneypunct}{thousands_sep}% -\indexlibrarymember{moneypunct}{grouping}% -\indexlibrarymember{moneypunct}{curr_symbol}% -\indexlibrarymember{moneypunct}{positive_sign}% -\indexlibrarymember{moneypunct}{negative_sign}% -\indexlibrarymember{moneypunct}{frac_digits}% -\indexlibrarymember{moneypunct}{positive_sign}% -\indexlibrarymember{moneypunct}{negative_sign}% -\begin{codeblock} -charT decimal_point() const; -charT thousands_sep() const; -string grouping() const; -string_type curr_symbol() const; -string_type positive_sign() const; -string_type negative_sign() const; -int frac_digits() const; -pattern pos_format() const; -pattern neg_format() const; -\end{codeblock} - -\pnum -Each of these functions \tcode{\placeholder{F}} -returns the result of calling the corresponding -virtual member function -\tcode{do_\placeholder{F}()}. - -\rSec4[locale.moneypunct.virtuals]{Virtual functions} - -\indexlibrarymember{moneypunct}{do_decimal_point}% -\begin{itemdecl} -charT do_decimal_point() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The radix separator to use -in case \tcode{do_frac_digits()} is greater than zero. -\begin{footnote} -In common U.S. locales this is \tcode{'.'}. -\end{footnote} -\end{itemdescr} - -\indexlibrarymember{moneypunct}{do_thousands_sep}% -\begin{itemdecl} -charT do_thousands_sep() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The digit group separator to use -in case \tcode{do_grouping()} specifies a digit grouping pattern. -\begin{footnote} -In common U.S. locales this is \tcode{','}. -\end{footnote} -\end{itemdescr} - -\indexlibrarymember{moneypunct}{do_grouping}% -\begin{itemdecl} -string do_grouping() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A pattern defined identically as, but not necessarily equal to, -the result of \tcode{numpunct::\brk{}do_grouping()}. -\begin{footnote} -To specify grouping by 3s, -the value is \tcode{"\textbackslash003"} \textit{not} \tcode{"3"}. -\end{footnote} -\end{itemdescr} - -\indexlibrarymember{moneypunct}{do_curr_symbol}% -\begin{itemdecl} -string_type do_curr_symbol() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A string to use as the currency identifier symbol. -\begin{note} -For specializations where the second template parameter is \tcode{true}, -this is typically four characters long: -a three-letter code as specified by ISO 4217 followed by a space. -\end{note} -\end{itemdescr} - -\indexlibrarymember{moneypunct}{do_positive_sign}% -\indexlibrarymember{moneypunct}{do_negative_sign}% -\begin{itemdecl} -string_type do_positive_sign() const; -string_type do_negative_sign() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_positive_sign()} -returns the string to use to indicate a positive monetary value; -\begin{footnote} -This is usually the empty string. -\end{footnote} -\tcode{do_negative_sign()} -returns the string to use to indicate a negative value. -\end{itemdescr} - -\indexlibrarymember{moneypunct}{do_frac_digits}% -\begin{itemdecl} -int do_frac_digits() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The number of digits after the decimal radix separator, if any. -\begin{footnote} -In common U.S.\ locales, this is 2. -\end{footnote} -\end{itemdescr} - -\indexlibrarymember{moneypunct}{do_pos_format}% -\indexlibrarymember{moneypunct}{do_neg_format}% -\begin{itemdecl} -pattern do_pos_format() const; -pattern do_neg_format() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The specializations required in \tref{locale.spec}\iref{locale.category}, namely -\begin{itemize} -\item \tcode{moneypunct}, -\item \tcode{moneypunct}, -\item \tcode{moneypunct}, and -\item \tcode{moneypunct}, -\end{itemize} -return an object of type \tcode{pattern} -initialized to \tcode{\{ symbol, sign, none, value \}}. -\begin{footnote} -Note that the international symbol returned by \tcode{do_curr_symbol()} -usually contains a space, itself; -for example, \tcode{"USD "}. -\end{footnote} -\end{itemdescr} - -\rSec3[locale.moneypunct.byname]{Class template \tcode{moneypunct_byname}} - -\indexlibraryglobal{moneypunct_byname}% -\begin{codeblock} -namespace std { - template - class moneypunct_byname : public moneypunct { - public: - using pattern = money_base::pattern; - using string_type = basic_string; - - explicit moneypunct_byname(const char*, size_t refs = 0); - explicit moneypunct_byname(const string&, size_t refs = 0); - - protected: - ~moneypunct_byname(); - }; -} -\end{codeblock} - -\rSec2[category.messages]{The message retrieval category} - -\rSec3[category.messages.general]{General} - -\pnum -Class \tcode{messages} -implements retrieval of strings from message catalogs. - -\rSec3[locale.messages]{Class template \tcode{messages}} - -\rSec4[locale.messages.general]{General} - -\indexlibraryglobal{messages}% -\begin{codeblock} -namespace std { - class messages_base { - public: - using catalog = @\textit{unspecified signed integer type}@; - }; - - template - class messages : public locale::facet, public messages_base { - public: - using char_type = charT; - using string_type = basic_string; - - explicit messages(size_t refs = 0); - - catalog open(const string& fn, const locale&) const; - string_type get(catalog c, int set, int msgid, - const string_type& dfault) const; - void close(catalog c) const; - - static locale::id id; - - protected: - ~messages(); - virtual catalog do_open(const string&, const locale&) const; - virtual string_type do_get(catalog, int set, int msgid, - const string_type& dfault) const; - virtual void do_close(catalog) const; - }; -} -\end{codeblock} - -\pnum -Values of type \tcode{messages_base::catalog} -usable as arguments to members \tcode{get} and \tcode{close} -can be obtained only by calling member \tcode{open}. - -\rSec4[locale.messages.members]{Members} - -\indexlibrarymember{messages}{open}% -\begin{itemdecl} -catalog open(const string& name, const locale& loc) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_open(name, loc)}. -\end{itemdescr} - -\indexlibrarymember{messages}{get}% -\begin{itemdecl} -string_type get(catalog cat, int set, int msgid, const string_type& dfault) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{do_get(cat, set, msgid, dfault)}. -\end{itemdescr} - -\indexlibrarymember{messages}{close}% -\begin{itemdecl} -void close(catalog cat) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{do_close(cat)}. -\end{itemdescr} - -\rSec4[locale.messages.virtuals]{Virtual functions} - -\indexlibrarymember{messages}{do_open}% -\begin{itemdecl} -catalog do_open(const string& name, const locale& loc) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A value that may be passed to \tcode{get()} -to retrieve a message from the message catalog -identified by the string \tcode{name} -according to an \impldef{mapping from name to catalog when calling -\tcode{mes\-sages::do_open}} mapping. -The result can be used until it is passed to \tcode{close()}. - -\pnum -Returns a value less than 0 if no such catalog can be opened. - -\pnum -\remarks -The locale argument \tcode{loc} is used for -character set code conversion when retrieving messages, if needed. -\end{itemdescr} - -\indexlibrarymember{messages}{do_get}% -\begin{itemdecl} -string_type do_get(catalog cat, int set, int msgid, const string_type& dfault) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{cat} is a catalog obtained from \tcode{open()} and not yet closed. - -\pnum -\returns -A message identified by -arguments \tcode{set}, \tcode{msgid}, and \tcode{dfault}, -according to -an \impldef{mapping to message when calling \tcode{messages::do_get}} mapping. -If no such message can be found, returns \tcode{dfault}. -\end{itemdescr} - -\indexlibrarymember{message}{do_close}% -\begin{itemdecl} -void do_close(catalog cat) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{cat} is a catalog obtained from \tcode{open()} and not yet closed. - -\pnum -\effects -Releases unspecified resources associated with \tcode{cat}. - -\pnum -\remarks -The limit on such resources, if any, is -\impldef{resource limits on a message catalog}. -\end{itemdescr} - -\rSec3[locale.messages.byname]{Class template \tcode{messages_byname}} - -\indexlibraryglobal{messages_byname}% -\begin{codeblock} -namespace std { - template - class messages_byname : public messages { - public: - using catalog = messages_base::catalog; - using string_type = basic_string; - - explicit messages_byname(const char*, size_t refs = 0); - explicit messages_byname(const string&, size_t refs = 0); - - protected: - ~messages_byname(); - }; -} -\end{codeblock} - -\rSec1[c.locales]{C library locales} - -\rSec2[clocale.syn]{Header \tcode{} synopsis} - -\indexlibraryglobal{lconv}% -\indexlibraryglobal{setlocale}% -\indexlibraryglobal{localeconv}% -\indexlibraryglobal{NULL}% -\indexlibraryglobal{LC_ALL}% -\indexlibraryglobal{LC_COLLATE}% -\indexlibraryglobal{LC_CTYPE}% -\indexlibraryglobal{LC_MONETARY}% -\indexlibraryglobal{LC_NUMERIC}% -\indexlibraryglobal{LC_TIME}% -\begin{codeblock} -namespace std { - struct lconv; - - char* setlocale(int category, const char* locale); - lconv* localeconv(); -} - -#define NULL @\textit{see \ref{support.types.nullptr}}@ -#define LC_ALL @\seebelow@ -#define LC_COLLATE @\seebelow@ -#define LC_CTYPE @\seebelow@ -#define LC_MONETARY @\seebelow@ -#define LC_NUMERIC @\seebelow@ -#define LC_TIME @\seebelow@ -\end{codeblock} - -\pnum -The contents and meaning of the header \libheaderdef{clocale} -are the same as the C standard library header \libheader{locale.h}. - -\rSec2[clocale.data.races]{Data races} - -\pnum -Calls to the function \tcode{setlocale} -may introduce a data race\iref{res.on.data.races} -with other calls to \tcode{setlocale} or -with calls to the functions listed in \tref{setlocale.data.races}. - -\xrefc{7.11} - -\begin{floattable} -{Potential \tcode{setlocale} data races} -{setlocale.data.races} -{lllll} -\topline - -\tcode{fprintf} & -\tcode{isprint} & -\tcode{iswdigit} & -\tcode{localeconv} & -\tcode{tolower} \\ - -\tcode{fscanf} & -\tcode{ispunct} & -\tcode{iswgraph} & -\tcode{mblen} & -\tcode{toupper} \\ - -\tcode{isalnum} & -\tcode{isspace} & -\tcode{iswlower} & -\tcode{mbstowcs} & -\tcode{towlower} \\ - -\tcode{isalpha} & -\tcode{isupper} & -\tcode{iswprint} & -\tcode{mbtowc} & -\tcode{towupper} \\ - -\tcode{isblank} & -\tcode{iswalnum} & -\tcode{iswpunct} & -\tcode{setlocale} & -\tcode{wcscoll} \\ - -\tcode{iscntrl} & -\tcode{iswalpha} & -\tcode{iswspace} & -\tcode{strcoll} & -\tcode{wcstod} \\ - -\tcode{isdigit} & -\tcode{iswblank} & -\tcode{iswupper} & -\tcode{strerror} & -\tcode{wcstombs} \\ - -\tcode{isgraph} & -\tcode{iswcntrl} & -\tcode{iswxdigit} & -\tcode{strtod} & -\tcode{wcsxfrm} \\ - -\tcode{islower} & -\tcode{iswctype} & -\tcode{isxdigit} & -\tcode{strxfrm} & -\tcode{wctomb} \\ -\end{floattable} - -\rSec1[text.encoding]{Text encodings identification} - -\rSec2[text.encoding.syn]{Header \tcode{} synopsis} - -\indexheader{text_encoding}% -\begin{codeblock} -namespace std { - struct text_encoding; - - // \ref{text.encoding.hash}, hash support - template struct hash; - template<> struct hash; -} -\end{codeblock} - -\rSec2[text.encoding.class]{Class \tcode{text_encoding}} - -\rSec3[text.encoding.overview]{Overview} - -\pnum -The class \tcode{text_encoding} describes an interface -for accessing the IANA Character Sets registry. - -\indexlibraryglobal{text_encoding}% -\begin{codeblock} -namespace std { - struct text_encoding { - static constexpr size_t max_name_length = 63; - - // \ref{text.encoding.id}, enumeration \tcode{text_encoding::id} - enum class id : int_least32_t { - @\seebelow@ - }; - using enum id; - - constexpr text_encoding() = default; - constexpr explicit text_encoding(string_view enc) noexcept; - constexpr text_encoding(id i) noexcept; - - constexpr id mib() const noexcept; - constexpr const char* name() const noexcept; - - struct aliases_view; - constexpr aliases_view aliases() const noexcept; - - friend constexpr bool operator==(const text_encoding& encoding, - const text_encoding& other) noexcept; - friend constexpr bool operator==(const text_encoding& encoding, id i) noexcept; - - static consteval text_encoding literal() noexcept; - static text_encoding environment(); - template static bool environment_is(); - - private: - id @\exposid{mib_}@ = id::unknown; // \expos - char @\exposid{name_}@[max_name_length + 1] = {0}; // \expos - static constexpr bool @\exposidnc{comp-name}@(string_view a, string_view b); // \expos - }; -} -\end{codeblock} - -\pnum -Class \tcode{text_encoding} is -a trivially copyable type\iref{term.trivially.copyable.type}. - -\rSec3[text.encoding.general]{General} - -\pnum -A \defnadj{registered character}{encoding} is -a character encoding scheme in the IANA Character Sets registry. -\begin{note} -The IANA Character Sets registry uses the term ``character sets'' -to refer to character encodings. -\end{note} -The primary name of a registered character encoding is -the name of that encoding specified in the IANA Character Sets registry. - -\pnum -The set of known registered character encodings contains -every registered character encoding -specified in the IANA Character Sets registry except for the following: -\begin{itemize} -\item NATS-DANO (33) -\item NATS-DANO-ADD (34) -\end{itemize} - -\pnum -Each known registered character encoding -is identified by an enumerator in \tcode{text_encoding::id}, and -has a set of zero or more \defnx{aliases}{encoding!registered character!alias}. - -\pnum -The set of aliases of a known registered character encoding is an -\impldef{set of aliases of a known registered character encoding} -superset of the aliases specified in the IANA Character Sets registry. -No two aliases or primary names of distinct registered character encodings -are equivalent when compared by \tcode{text_encoding::\exposid{comp-name}}. - -\pnum -How a \tcode{text_encoding} object -is determined to be representative of a character encoding scheme -implemented in the translation or execution environment is -\impldef{how \tcode{text_encoding} objects are -determined to be representative of a character encoding scheme}. - -\pnum -An object \tcode{e} of type \tcode{text_encoding} such that -\tcode{e.mib() == text_encoding::id::unknown} is \tcode{false} and -\tcode{e.mib() == text_encoding::id::other} is \tcode{false} -maintains the following invariants: -\begin{itemize} -\item \tcode{e.name() == nullptr} is \tcode{false}, and -\item \tcode{e.mib() == text_encoding(e.name()).mib()} is \tcode{true}. -\end{itemize} - -\pnum -\recommended -\begin{itemize} -\item -Implementations should not consider registered encodings to be interchangeable. -\begin{example} -Shift_JIS and Windows-31J denote different encodings. -\end{example} -\item -Implementations should not use the name of a registered encoding -to describe another similar yet different non-registered encoding -unless there is a precedent on that implementation. -\begin{example} -Big5 -\end{example} -\end{itemize} - -\rSec3[text.encoding.members]{Members} - -\indexlibraryctor{text_encoding}% -\begin{itemdecl} -constexpr explicit text_encoding(string_view enc) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\begin{itemize} -\item -\tcode{enc} represents a string in the ordinary literal encoding -consisting only of elements of the basic character set\iref{lex.charset}. -\item -\tcode{enc.size() <= max_name_length} is \tcode{true}. -\item -\tcode{enc.contains('\textbackslash 0')} is \tcode{false}. -\end{itemize} - -\pnum -\ensures -\begin{itemize} -\item -If there exists a primary name or alias \tcode{a} -of a known registered character encoding such that -\tcode{\exposid{comp-name}(a, enc)} is \tcode{true}, -\exposid{mib_} has the value of the enumerator of \tcode{id} -associated with that registered character encoding. -Otherwise, \tcode{\exposid{mib_} == id::other} is \tcode{true}. -\item -\tcode{enc.compare(\exposid{name_}) == 0} is \tcode{true}. -\end{itemize} -\end{itemdescr} - -\indexlibraryctor{text_encoding}% -\begin{itemdecl} -constexpr text_encoding(id i) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{i} has the value of one of the enumerators of \tcode{id}. - -\pnum -\ensures -\begin{itemize} -\item -\tcode{\exposid{mib_} == i} is \tcode{true}. -\item -If \tcode{(\exposid{mib_} == id::unknown || \exposid{mib_} == id::other)} -is \tcode{true}, -\tcode{strlen(\exposid{name_}) == 0} is \tcode{true}. -Otherwise, -\tcode{ranges::contains(aliases(), string_view(\exposid{name_}))} -is \tcode{true}. -\end{itemize} -\end{itemdescr} - -\indexlibrarymember{mib}{text_encoding}% -\begin{itemdecl} -constexpr id mib() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\exposid{mib_}. -\end{itemdescr} - -\indexlibrarymember{name}{text_encoding}% -\begin{itemdecl} -constexpr const char* name() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\exposid{name_} if \tcode{(\exposid{name_}[0] != '\textbackslash 0')} -is \tcode{true}, and -\keyword{nullptr} otherwise. - -\pnum -\remarks -If \tcode{name() == nullptr} is \tcode{false}, -\tcode{name()} is an \ntbs{} and -accessing elements of \exposid{name_} -outside of the range \countedrange{name()}{strlen(name()) + 1} -is undefined behavior. -\end{itemdescr} - -\indexlibrarymember{aliases}{text_encoding}% -\begin{itemdecl} -constexpr aliases_view aliases() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -Let \tcode{r} denote an instance of \tcode{aliases_view}. -If \tcode{*this} represents a known registered character encoding, then: -\begin{itemize} -\item -\tcode{r.front()} is the primary name of the registered character encoding, -\item -\tcode{r} contains the aliases of the registered character encoding, and -\item -\tcode{r} does not contain duplicate values when compared with \tcode{strcmp}. -\end{itemize} -Otherwise, \tcode{r} is an empty range. - -\pnum -Each element in \tcode{r} -is a non-null, non-empty \ntbs{} encoded in the literal character encoding and -comprising only characters from the basic character set. - -\pnum -\returns -\tcode{r}. - -\pnum -\begin{note} -The order of aliases in \tcode{r} is unspecified. -\end{note} -\end{itemdescr} - -\indexlibrarymember{literal}{text_encoding}% -\begin{itemdecl} -static consteval text_encoding literal() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{CHAR_BIT == 8} is \tcode{true}. - -\pnum -\returns -A \tcode{text_encoding} object representing -the ordinary character literal encoding\iref{lex.charset}. -\end{itemdescr} - -\indexlibrarymember{environment}{text_encoding}% -\begin{itemdecl} -static text_encoding environment(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{CHAR_BIT == 8} is \tcode{true}. - -\pnum -\returns -A \tcode{text_encoding} object representing -the \impldef{character encoding scheme of the environment} -character encoding scheme of the environment. -On a POSIX implementation, this is the encoding scheme associated with -the POSIX locale denoted by the empty string \tcode{""}. - -\pnum -\begin{note} -This function is not affected by calls to \tcode{setlocale}. -\end{note} - -\pnum -\recommended -Implementations should return a value that is not affected by calls to -the POSIX function \tcode{setenv} and -other functions which can modify the environment\iref{support.runtime}. -\end{itemdescr} - -\indexlibrarymember{environment_is}{text_encoding}% -\begin{itemdecl} -template - static bool environment_is(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{CHAR_BIT == 8} is \tcode{true}. - -\pnum -\returns -\tcode{environment() == i}. -\end{itemdescr} - -\indexlibrarymember{\exposid{comp-name}}{text_encoding}% -\begin{itemdecl} -static constexpr bool @\exposid{comp-name}@(string_view a, string_view b); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if the two strings \tcode{a} and \tcode{b} -encoded in the ordinary literal encoding -are equal, ignoring, from left-to-right, -\begin{itemize} -\item -all elements that are not digits or letters\iref{character.seq.general}, -\item -character case, and -\item -any sequence of one or more \tcode{0} characters -not immediately preceded by a numeric prefix, where -a numeric prefix is a sequence consisting of -a digit in the range \crange{1}{9} -optionally followed by one or more elements which are not digits or letters, -\end{itemize} -and \tcode{false} otherwise. - -\begin{note} -This comparison is identical to -the ``Charset Alias Matching'' algorithm -described in the Unicode Technical Standard 22. -\end{note} - -\begin{example} -\begin{codeblock} -static_assert(@\exposid{comp-name}@("UTF-8", "utf8") == true); -static_assert(@\exposid{comp-name}@("u.t.f-008", "utf8") == true); -static_assert(@\exposid{comp-name}@("ut8", "utf8") == false); -static_assert(@\exposid{comp-name}@("utf-80", "utf8") == false); -\end{codeblock} -\end{example} -\end{itemdescr} - -\rSec3[text.encoding.cmp]{Comparison functions} - -\indexlibrarymember{operator==}{text_encoding}% -\begin{itemdecl} -friend constexpr bool operator==(const text_encoding& a, const text_encoding& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -If \tcode{a.\exposid{mib_} == id::other \&\& b.\exposid{mib_} == id::other} -is \tcode{true}, -then \tcode{\exposid{comp-name}(a.\exposid{name_},\linebreak{}b.\exposid{name_})}. -Otherwise, \tcode{a.\exposid{mib_} == b.\exposid{mib_}}. -\end{itemdescr} - -\indexlibrarymember{operator==}{text_encoding}% -\begin{itemdecl} -friend constexpr bool operator==(const text_encoding& encoding, id i) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{encoding.\exposid{mib_} == i}. - -\pnum -\remarks -This operator induces an equivalence relation on its arguments -if and only if \tcode{i != id::other} is \tcode{true}. -\end{itemdescr} - -\rSec3[text.encoding.aliases]{Class text_encoding::aliases_view} - -\indexlibrarymember{aliases_view}{text_encoding}% -\indexlibrarymember{begin}{text_encoding::aliases_view}% -\indexlibrarymember{end}{text_encoding::aliases_view}% -\begin{itemdecl} -struct text_encoding::aliases_view : ranges::view_interface { - constexpr @\impdefx{type of \tcode{text_encoding::aliases_view::begin()}}@ begin() const; - constexpr @\impdefx{type of \tcode{text_encoding::aliases_view::end()}}@ end() const; -}; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\tcode{text_encoding::aliases_view} models -\libconcept{copyable}, -\tcode{ranges::\libconcept{view}}, -\tcode{ranges::\libconcept{random_access_range}}, and -\tcode{ranges::\libconcept{borrowed_range}}. - -\pnum -Both -\tcode{ranges::range_value_t} and -\tcode{ranges::range_reference_t} -denote \tcode{const char*}. -\end{itemdescr} - -\rSec3[text.encoding.id]{Enumeration \tcode{text_encoding::id}} - -\indexlibrarymember{id}{text_encoding}% -\begin{codeblock} -namespace std { - enum class text_encoding::id : int_least32_t { - other = 1, - unknown = 2, - ASCII = 3, - ISOLatin1 = 4, - ISOLatin2 = 5, - ISOLatin3 = 6, - ISOLatin4 = 7, - ISOLatinCyrillic = 8, - ISOLatinArabic = 9, - ISOLatinGreek = 10, - ISOLatinHebrew = 11, - ISOLatin5 = 12, - ISOLatin6 = 13, - ISOTextComm = 14, - HalfWidthKatakana = 15, - JISEncoding = 16, - ShiftJIS = 17, - EUCPkdFmtJapanese = 18, - EUCFixWidJapanese = 19, - ISO4UnitedKingdom = 20, - ISO11SwedishForNames = 21, - ISO15Italian = 22, - ISO17Spanish = 23, - ISO21German = 24, - ISO60DanishNorwegian = 25, - ISO69French = 26, - ISO10646UTF1 = 27, - ISO646basic1983 = 28, - INVARIANT = 29, - ISO2IntlRefVersion = 30, - NATSSEFI = 31, - NATSSEFIADD = 32, - ISO10Swedish = 35, - KSC56011987 = 36, - ISO2022KR = 37, - EUCKR = 38, - ISO2022JP = 39, - ISO2022JP2 = 40, - ISO13JISC6220jp = 41, - ISO14JISC6220ro = 42, - ISO16Portuguese = 43, - ISO18Greek7Old = 44, - ISO19LatinGreek = 45, - ISO25French = 46, - ISO27LatinGreek1 = 47, - ISO5427Cyrillic = 48, - ISO42JISC62261978 = 49, - ISO47BSViewdata = 50, - ISO49INIS = 51, - ISO50INIS8 = 52, - ISO51INISCyrillic = 53, - ISO54271981 = 54, - ISO5428Greek = 55, - ISO57GB1988 = 56, - ISO58GB231280 = 57, - ISO61Norwegian2 = 58, - ISO70VideotexSupp1 = 59, - ISO84Portuguese2 = 60, - ISO85Spanish2 = 61, - ISO86Hungarian = 62, - ISO87JISX0208 = 63, - ISO88Greek7 = 64, - ISO89ASMO449 = 65, - ISO90 = 66, - ISO91JISC62291984a = 67, - ISO92JISC62991984b = 68, - ISO93JIS62291984badd = 69, - ISO94JIS62291984hand = 70, - ISO95JIS62291984handadd = 71, - ISO96JISC62291984kana = 72, - ISO2033 = 73, - ISO99NAPLPS = 74, - ISO102T617bit = 75, - ISO103T618bit = 76, - ISO111ECMACyrillic = 77, - ISO121Canadian1 = 78, - ISO122Canadian2 = 79, - ISO123CSAZ24341985gr = 80, - ISO88596E = 81, - ISO88596I = 82, - ISO128T101G2 = 83, - ISO88598E = 84, - ISO88598I = 85, - ISO139CSN369103 = 86, - ISO141JUSIB1002 = 87, - ISO143IECP271 = 88, - ISO146Serbian = 89, - ISO147Macedonian = 90, - ISO150 = 91, - ISO151Cuba = 92, - ISO6937Add = 93, - ISO153GOST1976874 = 94, - ISO8859Supp = 95, - ISO10367Box = 96, - ISO158Lap = 97, - ISO159JISX02121990 = 98, - ISO646Danish = 99, - USDK = 100, - DKUS = 101, - KSC5636 = 102, - Unicode11UTF7 = 103, - ISO2022CN = 104, - ISO2022CNEXT = 105, - UTF8 = 106, - ISO885913 = 109, - ISO885914 = 110, - ISO885915 = 111, - ISO885916 = 112, - GBK = 113, - GB18030 = 114, - OSDEBCDICDF0415 = 115, - OSDEBCDICDF03IRV = 116, - OSDEBCDICDF041 = 117, - ISO115481 = 118, - KZ1048 = 119, - UCS2 = 1000, - UCS4 = 1001, - UnicodeASCII = 1002, - UnicodeLatin1 = 1003, - UnicodeJapanese = 1004, - UnicodeIBM1261 = 1005, - UnicodeIBM1268 = 1006, - UnicodeIBM1276 = 1007, - UnicodeIBM1264 = 1008, - UnicodeIBM1265 = 1009, - Unicode11 = 1010, - SCSU = 1011, - UTF7 = 1012, - UTF16BE = 1013, - UTF16LE = 1014, - UTF16 = 1015, - CESU8 = 1016, - UTF32 = 1017, - UTF32BE = 1018, - UTF32LE = 1019, - BOCU1 = 1020, - UTF7IMAP = 1021, - Windows30Latin1 = 2000, - Windows31Latin1 = 2001, - Windows31Latin2 = 2002, - Windows31Latin5 = 2003, - HPRoman8 = 2004, - AdobeStandardEncoding = 2005, - VenturaUS = 2006, - VenturaInternational = 2007, - DECMCS = 2008, - PC850Multilingual = 2009, - PC8DanishNorwegian = 2012, - PC862LatinHebrew = 2013, - PC8Turkish = 2014, - IBMSymbols = 2015, - IBMThai = 2016, - HPLegal = 2017, - HPPiFont = 2018, - HPMath8 = 2019, - HPPSMath = 2020, - HPDesktop = 2021, - VenturaMath = 2022, - MicrosoftPublishing = 2023, - Windows31J = 2024, - GB2312 = 2025, - Big5 = 2026, - Macintosh = 2027, - IBM037 = 2028, - IBM038 = 2029, - IBM273 = 2030, - IBM274 = 2031, - IBM275 = 2032, - IBM277 = 2033, - IBM278 = 2034, - IBM280 = 2035, - IBM281 = 2036, - IBM284 = 2037, - IBM285 = 2038, - IBM290 = 2039, - IBM297 = 2040, - IBM420 = 2041, - IBM423 = 2042, - IBM424 = 2043, - PC8CodePage437 = 2011, - IBM500 = 2044, - IBM851 = 2045, - PCp852 = 2010, - IBM855 = 2046, - IBM857 = 2047, - IBM860 = 2048, - IBM861 = 2049, - IBM863 = 2050, - IBM864 = 2051, - IBM865 = 2052, - IBM868 = 2053, - IBM869 = 2054, - IBM870 = 2055, - IBM871 = 2056, - IBM880 = 2057, - IBM891 = 2058, - IBM903 = 2059, - IBM904 = 2060, - IBM905 = 2061, - IBM918 = 2062, - IBM1026 = 2063, - IBMEBCDICATDE = 2064, - EBCDICATDEA = 2065, - EBCDICCAFR = 2066, - EBCDICDKNO = 2067, - EBCDICDKNOA = 2068, - EBCDICFISE = 2069, - EBCDICFISEA = 2070, - EBCDICFR = 2071, - EBCDICIT = 2072, - EBCDICPT = 2073, - EBCDICES = 2074, - EBCDICESA = 2075, - EBCDICESS = 2076, - EBCDICUK = 2077, - EBCDICUS = 2078, - Unknown8BiT = 2079, - Mnemonic = 2080, - Mnem = 2081, - VISCII = 2082, - VIQR = 2083, - KOI8R = 2084, - HZGB2312 = 2085, - IBM866 = 2086, - PC775Baltic = 2087, - KOI8U = 2088, - IBM00858 = 2089, - IBM00924 = 2090, - IBM01140 = 2091, - IBM01141 = 2092, - IBM01142 = 2093, - IBM01143 = 2094, - IBM01144 = 2095, - IBM01145 = 2096, - IBM01146 = 2097, - IBM01147 = 2098, - IBM01148 = 2099, - IBM01149 = 2100, - Big5HKSCS = 2101, - IBM1047 = 2102, - PTCP154 = 2103, - Amiga1251 = 2104, - KOI7switched = 2105, - BRF = 2106, - TSCII = 2107, - CP51932 = 2108, - windows874 = 2109, - windows1250 = 2250, - windows1251 = 2251, - windows1252 = 2252, - windows1253 = 2253, - windows1254 = 2254, - windows1255 = 2255, - windows1256 = 2256, - windows1257 = 2257, - windows1258 = 2258, - TIS620 = 2259, - CP50220 = 2260 - }; -} -\end{codeblock} - -\begin{note} -The \tcode{text_encoding::id} enumeration -contains an enumerator for each known registered character encoding. -For each encoding, the corresponding enumerator is derived from -the alias beginning with ``\tcode{cs}'', as follows -\begin{itemize} -\item -\tcode{csUnicode} is mapped to \tcode{text_encoding::id::UCS2}, -\item -\tcode{csIBBM904} is mapped to \tcode{text_encoding::id::IBM904}, and -\item -the ``\tcode{cs}'' prefix is removed from other names. -\end{itemize} -\end{note} - -\rSec3[text.encoding.hash]{Hash support} - -\indexlibrarymember{hash}{text_encoding}% -\begin{itemdecl} -template<> struct hash; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The specialization is enabled\iref{unord.hash}. -\end{itemdescr} diff --git a/source/macros.tex b/source/macros.tex index f8c3e2b720..ec88684fcd 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -39,20 +39,18 @@ \newenvironment{addedblock}{\color{addclr}}{\color{black}} \newenvironment{removedblock}{\color{remclr}}{\color{black}} -%%-------------------------------------------------- +%%------------------------------------------------------------- %% Grammar extraction. -%%-------------------------------------------------- -\def\gramSec[#1]#2{} - +%% Assumes that the output file \gramout is managed externally. +%%------------------------------------------------------------- \makeatletter -\newcommand{\FlushAndPrintGrammar}{% -\immediate\closeout\XTR@out% -\immediate\openout\XTR@out=std-gram-dummy.tmp% -\def\gramSec[##1]##2{\rSec1[##1]{##2}}% -\input{std-gram.ext}% -} +\newcommand{\gramWrite}[1]{\protected@write\gramout{}{#1}} +\newcommand{\meaningbody}[1]{\expandafter\strip@prefix\meaning#1} \makeatother +\newcommand{\gramSec}[2][]{\gramWrite{% +\string\rSec1\string[\string#1\string]\string{\string#2\string}}} + %%-------------------------------------------------- % Escaping for index entries. Replaces ! with "! throughout its argument. %%-------------------------------------------------- @@ -78,12 +76,12 @@ % Set the xref label for a clause to be "Clause n", not just "n". \makeatletter -\newcommand{\customlabel}[2]{% -\@bsphack \begingroup \protected@edef \@currentlabel {\protect \M@TitleReference{#2}{\M@currentTitle}}\MNR@label{#1}\endgroup \@esphack% +\newcommand{\customlabel}[3]{% +\@bsphack \protected@write\@auxout{}{\string\newlabel{#1}{{#3}{\thepage}{}{#2.\thechapter}{}}} \@esphack% } \makeatother -\newcommand{\clauselabel}[1]{\customlabel{#1}{Clause \thechapter}} -\newcommand{\annexlabel}[1]{\customlabel{#1}{Annex \thechapter}} +\newcommand{\clauselabel}[1]{\customlabel{#1}{chapter}{Clause \thechapter}} +\newcommand{\annexlabel}[1]{\customlabel{#1}{appendix}{Annex \thechapter}} % Use prefix "Annex" in the table of contents \newcommand{\annexnumberlinebox}[2]{Annex #2\space} @@ -120,6 +118,11 @@ \addtocounter{SectionDepth}{\value{SectionDepthBase}} \Sec{\arabic{SectionDepth}}[#2]{#3}} +%%-------------------------------------------------- +% Bibliography +%%-------------------------------------------------- +\newcommand{\supercite}[1]{\textsuperscript{\cite{#1}}} + %%-------------------------------------------------- % Indexing %%-------------------------------------------------- @@ -142,7 +145,7 @@ % \indeximpldef synthesizes a collation key from the argument; that is, an % invocation \indeximpldef{arg} emits an index entry `key@arg`, where `key` -% is derived from `arg` by replacing the folowing list of commands with their +% is derived from `arg` by replacing the following list of commands with their % bare content. This allows, say, collating plain text and code. \newcommand{\indeximpldef}[1]{% \let\otextup\textup% @@ -209,12 +212,21 @@ \newcommand{\libmember}[2]{\indexlibrarymember{#1}{#2}#1} \newcommand{\libspec}[2]{\indexlibrarymemberx{#1}{#2}#1} +% index for macros +% \libmacro is suitable for use directly in header synopses to add the macro +% to both the text and the library index. \libxmacro does the same, but +% prepends a well-rendered double underscore. +\newcommand{\libmacro}[1]{\indexlibraryglobal{#1}\CodeStylex{#1}} +\newcommand{\libxmacro}[1]{\indexlibraryglobal{\idxxname{#1}}\CodeStylex{\xname{#1}}} + % index for library headers -\newcommand{\libheader}[1]{\indexhdr{#1}\tcode{<#1>}} +\newcommand{\libheaderx}[2]{\indexhdr{#1}\tcode{<#2>}} +\newcommand{\libheader}[1]{\libheaderx{#1}{#1}} \newcommand{\indexheader}[1]{\index[headerindex]{\idxhdr{#1}|idxbfpage}} \newcommand{\libheaderdef}[1]{\indexheader{#1}\tcode{<#1>}} \newcommand{\libnoheader}[1]{\indextext{\idxhdr{#1}!absence thereof}\tcode{<#1>}} -\newcommand{\libheaderrefx}[2]{\libheader{#1}\iref{#2}} +\newcommand{\libheaderrefxx}[3]{\libheaderx{#1}{#2}\iref{#3}} +\newcommand{\libheaderrefx}[2]{\libheaderrefxx{#1}{#1}{#2}} \newcommand{\libheaderref}[1]{\libheaderrefx{#1}{#1.syn}} \newcommand{\libdeprheaderref}[1]{\libheaderrefx{#1}{depr.#1.syn}} @@ -281,6 +293,9 @@ \newcommand{\CppXXVI}{\Cpp{} 2026} \newcommand{\IsoCUndated}{ISO/IEC 9899} \newcommand{\IsoC}{\IsoCUndated{}:2018} +\newcommand{\IsoFloatUndated}{ISO/IEC 60559} +\newcommand{\IsoPosixUndated}{ISO/IEC/IEEE 9945} +\newcommand{\IsoPosix}{\IsoPosixUndated{}:2009} \newcommand{\opt}[1]{#1\ensuremath{_\mathit{\color{black}opt}}} \newcommand{\bigoh}[1]{\ensuremath{\mathscr{O}(#1)}} @@ -313,7 +328,7 @@ \newcommand{\newnoteenvironment}[3]{ \newsubclausecounter{#1} \newenvironment{tail#1} -{\par\small\stepcounter{#1}\noteintro{#2}} +{\par\small\penalty -200\stepcounter{#1}\noteintro{#2}} {\noteoutro{#3}} \newenvironment{#1} {\begin{tail#1}} @@ -349,6 +364,7 @@ \newcommand{\constraints}{\Fundesc{Constraints}} \newcommand{\mandates}{\Fundesc{Mandates}} \newcommand{\expects}{\Fundesc{Preconditions}} +\newcommand{\hardexpects}{\Fundesc{Hardened preconditions}} \newcommand{\effects}{\Fundesc{Effects}} \newcommand{\ensures}{\Fundesc{Postconditions}} \newcommand{\returns}{\Fundesc{Returns}} @@ -359,15 +375,15 @@ \newcommand{\errors}{\Fundesc{Error conditions}} \newcommand{\sync}{\Fundesc{Synchronization}} \newcommand{\implimits}{\Fundesc{Implementation limits}} -\newcommand{\replaceable}{\Fundesc{Replaceable}} \newcommand{\result}{\Fundesc{Result}} \newcommand{\returntype}{\Fundesc{Return type}} \newcommand{\ctype}{\Fundesc{Type}} \newcommand{\templalias}{\Fundesc{Alias template}} %% Cross-reference -\newcommand{\xref}{\textsc{See also:}\space} -\newcommand{\xrefc}[1]{\xref{} \IsoC{}, #1} +\newcommand{\xref}[1]{\textsc{See also:}\space #1} +\newcommand{\xrefc}[1]{\xref{\IsoC{}, #1}} +\newcommand{\termref}[3]{\textit{#2}{#3}\iref{#1}} % in Clause 3 %% Inline comma-separated parenthesized references \ExplSyntaxOn @@ -538,6 +554,9 @@ \newcommand{\cv}{\ifmmode\mathit{cv}\else\cvqual{cv}\fi} \newcommand{\numconst}[1]{\textsl{#1}} \newcommand{\logop}[1]{\textsc{#1}} +\DeclareMathOperator{\mullo}{mullo} +\DeclareMathOperator{\mulhi}{mulhi} +\newcommand{\cedef}{\mathrel{\mathop:}=} % "colon-equals definition" %%-------------------------------------------------- %% Environments for code listings. @@ -573,22 +592,6 @@ \lstnewenvironment{codeblock}{\CodeBlockSetup}{} -% Left-align listings titles -\makeatletter -\def\lst@maketitle{\@makeleftcaption\lst@title@dropdelim} -\long\def\@makeleftcaption#1#2{% - \vskip\abovecaptionskip - \sbox\@tempboxa{#1: #2}% - \ifdim \wd\@tempboxa >\hsize - #1: #2\par - \else - \global \@minipagefalse - \hb@xt@\hsize{%\hfil -- REMOVED - \box\@tempboxa\hfil}% - \fi - \vskip\belowcaptionskip}% -\makeatother - \lstnewenvironment{codeblocktu}[1]{% \lstset{title={%\parabullnum{Bullets1}{0pt} #1:}}\CodeBlockSetup}{} @@ -608,6 +611,17 @@ \newcommand{\atsign}{@} \makeatother +%%-------------------------------------------------- +%% Formulae +%%-------------------------------------------------- + +% usage: \begin{formula}{XREF} +\newenvironment{formula}[1] +{\begin{equation}\label{eq:#1}} +{\end{equation}} + +\renewcommand{\eqref}[1]{Formula \nolinebreak[3] \hyperref[eq:#1]{\ref*{eq:#1}}} + %%-------------------------------------------------- %% Indented text %%-------------------------------------------------- @@ -622,9 +636,9 @@ { \lstset{escapechar=@, xleftmargin=0em, - midpenalty=500, + midpenalty=3000, semicolonpenalty=-50, - endpenalty=3000, + endpenalty=2000, aboveskip=2ex, belowskip=0ex % leave this alone: it keeps these things out of the % footnote area @@ -651,7 +665,17 @@ \setlength{\BnfInc}{\BnfIndent} \newlength{\BnfRest} \setlength{\BnfRest}{2\BnfIndent} -\newcommand{\BnfNontermshape}{\small\color{grammar-gray}\sffamily\itshape} +\newcommand{\BnfNontermshape}{% + \small% + \color{grammar-gray}% + % The color setting inserts a \pdfcolorstack entry into the vertical list, + % breaking the connection of the \penalty entry from a preceding heading + % with the \glue entries that precede the grammar snippet. + % Add a penalty here that prevents making those \glue entries page-breaking + % opportunities. + \penalty10000% + \sffamily% + \itshape} \newcommand{\BnfReNontermshape}{\small\rmfamily\itshape} \newcommand{\BnfTermshape}{\small\ttfamily\upshape} @@ -675,7 +699,12 @@ \nonfrenchspacing } -\newenvironment{simplebnf} +% "ncbnf" is the non-copied "base" versions of the bnf environment; +% instances of the full "bnf" environment is copied to the grammar +% extraction file. +% (Similarly for "ncsimplebnf", though in fact we never extract any +% hypothetical "simplebnf" environments.) +\newenvironment{ncsimplebnf} { \begin{bnfbase} \BnfNontermshape @@ -686,7 +715,7 @@ \end{bnfbase} } -\newenvironment{bnf} +\newenvironment{ncbnf} { \begin{bnfbase} \begin{bnflist} @@ -698,6 +727,7 @@ \end{bnfbase} } +% The regex grammar is never copied. \newenvironment{ncrebnf} { \begin{bnfbase} @@ -711,11 +741,10 @@ \end{bnfbase} } -% non-copied versions of bnf environments -\let\ncsimplebnf\simplebnf -\let\endncsimplebnf\endsimplebnf -\let\ncbnf\bnf -\let\endncbnf\endbnf +\NewEnviron{bnf}{\begin{ncbnf}% +\BODY% +\gramWrite{\string\begin{ncbnf}\meaningbody\BODY\string\end{ncbnf}}% +\end{ncbnf}}{} %%-------------------------------------------------- %% Environment for imported graphics diff --git a/source/memory.tex b/source/memory.tex index d3bc9c6071..dfa3087c95 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -13,14 +13,15 @@ \begin{libsumtab}{Memory management library summary}{mem.summary} \ref{memory} & Memory & \tcode{}, \tcode{} \\ \rowsep -\ref{smartptr} & Smart pointers & \tcode{} \\ \rowsep -\ref{mem.res} & Memory resources & \tcode{} \\ \rowsep +\ref{smartptr} & Smart pointers & \tcode{} \\ \rowsep +\ref{mem.composite.types} & Types for composite class design & \tcode{} \\ \rowsep +\ref{mem.res} & Memory resources & \tcode{} \\ \rowsep \ref{allocator.adaptor} & Scoped allocators & \tcode{} \\ \end{libsumtab} \rSec1[memory]{Memory} -\rSec2[memory.general]{In general} +\rSec2[memory.general]{General} \pnum Subclause~\ref{memory} describes the contents of the header @@ -82,7 +83,9 @@ // \ref{ptr.align}, pointer alignment void* align(size_t alignment, size_t size, void*& ptr, size_t& space); // freestanding template - [[nodiscard]] constexpr T* assume_aligned(T* ptr); // freestanding + constexpr T* assume_aligned(T* ptr); // freestanding + template + bool is_sufficiently_aligned(T* ptr); // \ref{obj.lifetime}, explicit lifetime management template @@ -102,6 +105,10 @@ template const volatile T* start_lifetime_as_array(const volatile void* p, // freestanding size_t n) noexcept; + template + T* trivially_relocate(T* first, T* last, T* result); // freestanding + template + constexpr T* relocate(T* first, T* last, T* result); // freestanding // \ref{allocator.tag}, allocator argument tag struct allocator_arg_t { explicit allocator_arg_t() = default; }; // freestanding @@ -185,76 +192,83 @@ concept @\exposconcept{nothrow-forward-range}@ = @\seebelow@; // \expos template - void uninitialized_default_construct(NoThrowForwardIterator first, // freestanding - NoThrowForwardIterator last); + constexpr void uninitialized_default_construct(NoThrowForwardIterator first, // freestanding + NoThrowForwardIterator last); template - void uninitialized_default_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, + void uninitialized_default_construct(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator last); template - NoThrowForwardIterator + constexpr NoThrowForwardIterator uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); // freestanding template NoThrowForwardIterator - uninitialized_default_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n); + uninitialized_default_construct_n(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} + Size n); namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> - I uninitialized_default_construct(I first, S last); // freestanding + constexpr I uninitialized_default_construct(I first, S last); // freestanding template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> - borrowed_iterator_t uninitialized_default_construct(R&& r); // freestanding + constexpr borrowed_iterator_t uninitialized_default_construct(R&& r); // freestanding template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> - I uninitialized_default_construct_n(I first, iter_difference_t n); // freestanding + constexpr I uninitialized_default_construct_n(I first, // freestanding + iter_difference_t n); } template - void uninitialized_value_construct(NoThrowForwardIterator first, // freestanding - NoThrowForwardIterator last); + constexpr void uninitialized_value_construct(NoThrowForwardIterator first, // freestanding + NoThrowForwardIterator last); template - void uninitialized_value_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, + void uninitialized_value_construct(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator last); template - NoThrowForwardIterator + constexpr NoThrowForwardIterator uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); // freestanding template NoThrowForwardIterator - uninitialized_value_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n); + uninitialized_value_construct_n(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} + Size n); namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> - I uninitialized_value_construct(I first, S last); // freestanding + constexpr I uninitialized_value_construct(I first, S last); // freestanding template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> - borrowed_iterator_t uninitialized_value_construct(R&& r); // freestanding + constexpr borrowed_iterator_t uninitialized_value_construct(R&& r); // freestanding template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> - I uninitialized_value_construct_n(I first, iter_difference_t n); // freestanding + constexpr I uninitialized_value_construct_n(I first, // freestanding + iter_difference_t n); } template - NoThrowForwardIterator uninitialized_copy(InputIterator first, // freestanding - InputIterator last, - NoThrowForwardIterator result); + constexpr NoThrowForwardIterator uninitialized_copy(InputIterator first, // freestanding + InputIterator last, + NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, ForwardIterator last, + NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // freestanding-deleted, + ForwardIterator first, // see \ref{algorithms.parallel.overloads} + ForwardIterator last, NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, // freestanding - NoThrowForwardIterator result); + constexpr NoThrowForwardIterator uninitialized_copy_n(InputIterator first, // freestanding + Size n, + NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, Size n, + NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // freestanding-deleted, + ForwardIterator first, // see \ref{algorithms.parallel.overloads} + Size n, NoThrowForwardIterator result); namespace ranges { @@ -263,39 +277,41 @@ template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_reference_t> - uninitialized_copy_result + constexpr uninitialized_copy_result uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); // freestanding template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_reference_t> - uninitialized_copy_result, borrowed_iterator_t> + constexpr uninitialized_copy_result, borrowed_iterator_t> uninitialized_copy(IR&& in_range, OR&& out_range); // freestanding template using uninitialized_copy_n_result = in_out_result; // freestanding template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_reference_t> - uninitialized_copy_n_result + constexpr uninitialized_copy_n_result uninitialized_copy_n(I ifirst, iter_difference_t n, // freestanding O ofirst, S olast); } template - NoThrowForwardIterator uninitialized_move(InputIterator first, // freestanding - InputIterator last, - NoThrowForwardIterator result); + constexpr NoThrowForwardIterator uninitialized_move(InputIterator first, // freestanding + InputIterator last, + NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, ForwardIterator last, + NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // freestanding-deleted, + ForwardIterator first, // see \ref{algorithms.parallel.overloads} + ForwardIterator last, NoThrowForwardIterator result); template - pair + constexpr pair uninitialized_move_n(InputIterator first, Size n, // freestanding NoThrowForwardIterator result); template pair - uninitialized_move_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, Size n, NoThrowForwardIterator result); + uninitialized_move_n(ExecutionPolicy&& exec, // freestanding-deleted, + ForwardIterator first, Size n, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator result); namespace ranges { template @@ -303,11 +319,11 @@ template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> - uninitialized_move_result + constexpr uninitialized_move_result uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); // freestanding template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_rvalue_reference_t> - uninitialized_move_result, borrowed_iterator_t> + constexpr uninitialized_move_result, borrowed_iterator_t> uninitialized_move(IR&& in_range, OR&& out_range); // freestanding template @@ -315,37 +331,40 @@ template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> - uninitialized_move_n_result + constexpr uninitialized_move_n_result uninitialized_move_n(I ifirst, iter_difference_t n, // freestanding O ofirst, S olast); } template - void uninitialized_fill(NoThrowForwardIterator first, // freestanding - NoThrowForwardIterator last, const T& x); + constexpr void uninitialized_fill(NoThrowForwardIterator first, // freestanding + NoThrowForwardIterator last, const T& x); template - void uninitialized_fill(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, NoThrowForwardIterator last, + void uninitialized_fill(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator last, const T& x); template - NoThrowForwardIterator + constexpr NoThrowForwardIterator uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); // freestanding template NoThrowForwardIterator - uninitialized_fill_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n, const T& x); + uninitialized_fill_n(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} + Size n, const T& x); namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T> requires @\libconcept{constructible_from}@, const T&> - I uninitialized_fill(I first, S last, const T& x); // freestanding + constexpr I uninitialized_fill(I first, S last, const T& x); // freestanding template<@\exposconcept{nothrow-forward-range}@ R, class T> requires @\libconcept{constructible_from}@, const T&> - borrowed_iterator_t uninitialized_fill(R&& r, const T& x); // freestanding + constexpr borrowed_iterator_t uninitialized_fill(R&& r, const T& x); // freestanding template<@\exposconcept{nothrow-forward-iterator}@ I, class T> requires @\libconcept{constructible_from}@, const T&> - I uninitialized_fill_n(I first, iter_difference_t n, const T& x); // freestanding + constexpr I uninitialized_fill_n(I first, // freestanding + iter_difference_t n, const T& x); } // \ref{specialized.construct}, \tcode{construct_at} @@ -364,14 +383,15 @@ constexpr void destroy(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last); template - void destroy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, NoThrowForwardIterator last); + void destroy(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator last); template constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, // freestanding Size n); template - NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n); + NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // freestanding-deleted, + NoThrowForwardIterator first, Size n); // see \ref{algorithms.parallel.overloads} namespace ranges { template<@\libconcept{destructible}@ T> @@ -570,19 +590,35 @@ // \ref{out.ptr.t}, class template \tcode{out_ptr_t} template - class out_ptr_t; + class out_ptr_t; // freestanding // \ref{out.ptr}, function template \tcode{out_ptr} template - auto out_ptr(Smart& s, Args&&... args); + auto out_ptr(Smart& s, Args&&... args); // freestanding // \ref{inout.ptr.t}, class template \tcode{inout_ptr_t} template - class inout_ptr_t; + class inout_ptr_t; // freestanding // \ref{inout.ptr}, function template \tcode{inout_ptr} template - auto inout_ptr(Smart& s, Args&&... args); + auto inout_ptr(Smart& s, Args&&... args); // freestanding + + // \ref{indirect}, class template \tcode{indirect} + template> + class indirect; + + // \ref{indirect.hash}, hash support + template struct hash>; + + // \ref{polymorphic}, class template \tcode{polymorphic} + template> + class polymorphic; + + namespace pmr { + template using indirect = indirect>; + template using polymorphic = polymorphic>; + } } \end{codeblock} @@ -829,7 +865,7 @@ \indexlibraryglobal{assume_aligned}% \begin{itemdecl} template - [[nodiscard]] constexpr T* assume_aligned(T* ptr); + constexpr T* assume_aligned(T* ptr); \end{itemdecl} \begin{itemdescr} @@ -839,9 +875,9 @@ \pnum \expects -\tcode{ptr} points to an object \tcode{X} of +\tcode{ptr} points to an object $X$ of a type similar\iref{conv.qual} to \tcode{T}, -where \tcode{X} has alignment \tcode{N}\iref{basic.align}. +where $X$ has alignment \tcode{N}\iref{basic.align}. \pnum \returns @@ -853,17 +889,39 @@ \pnum \begin{note} -The alignment assumption on an object \tcode{X} +The alignment assumption on an object $X$ expressed by a call to \tcode{assume_aligned} might result in generation of more efficient code. It is up to the program to ensure that the assumption actually holds. The call does not cause the implementation to verify or enforce this. An implementation might only make the assumption -for those operations on \tcode{X} that access \tcode{X} +for those operations on $X$ that access $X$ through the pointer returned by \tcode{assume_aligned}. \end{note} \end{itemdescr} +\indexlibraryglobal{is_sufficiently_aligned}% +\begin{itemdecl} +template + bool is_sufficiently_aligned(T* ptr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{p} points to +an object \tcode{X} of a type similar\iref{conv.qual} to \tcode{T}. + +\pnum +\returns +\tcode{true} if \tcode{X} has alignment at least \tcode{Alignment}, +otherwise \tcode{false}. + +\pnum +\throws +Nothing. +\end{itemdescr} + \rSec2[obj.lifetime]{Explicit lifetime management} \indexlibraryglobal{start_lifetime_as}% @@ -961,6 +1019,128 @@ a pointer that compares equal to \tcode{p}\iref{expr.eq}. \end{itemdescr} +\indexlibraryglobal{trivially_relocate}% +\begin{itemdecl} +template + T* trivially_relocate(T* first, T* last, T* result); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_trivially_relocatable_v \&\& !is_const_v} is \tcode{true}. +\tcode{T} is not an array of unknown bound. + +\pnum +\expects +\begin{itemize} +\item + \range{first}{last} is a valid range. +\item + \range{result}{result + (last - first)} denotes a region of storage that + is a subset of the region reachable through \tcode{result}\iref{basic.compound} + and suitably aligned for the type \tcode{T}. +\item + No element in the range \range{first}{last} is a potentially-overlapping subobject. +\end{itemize} + +\pnum +\ensures +No effect if \tcode{result == first} is \tcode{true}. +Otherwise, the range denoted by \range{result}{result + (last - first)} +contains objects (including subobjects) whose lifetime has begun and whose +object representations are the original object representations of the +corresponding objects in the source range \range{first}{last} except +for any parts of the object representations used by the implementation to +represent type information\iref{intro.object}. If any of the objects has +union type, its active member is the same as that of the corresponding object +in the source range. If any of the aforementioned objects has a non-static +data member of reference type, that reference refers to the same entity as +does the corresponding reference in the source range. The lifetimes of the +original objects in the source range have ended. + +\pnum +\returns +\tcode{result + (last - first)}. + +\pnum +\throws +Nothing. + +\pnum +\complexity +Linear in the length of the source range. + +\pnum +\remarks +The destination region of storage is considered reused\iref{basic.life}. +No constructors or destructors are invoked. + +\begin{note} +Overlapping ranges are supported. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{relocate}% +\begin{itemdecl} +template + constexpr T* relocate(T* first, T* last, T* result); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_nothrow_relocatable_v \&\& !is_const_v} is \tcode{true}. +\tcode{T} is not an array of unknown bound. + +\pnum +\expects +\begin{itemize} +\item + \range{first}{last} is a valid range. +\item + \range{result}{result + (last - first)} denotes a region of storage that is + a subset of the region reachable through \tcode{result}\iref{basic.compound} + and suitably aligned for the type \tcode{T}. +\item + No element in the range \range{first}{last} is a potentially-overlapping + subobject. +\end{itemize} + +\pnum +\effects +\begin{itemize} +\item + If \tcode{result == first} is \tcode{true}, no effect; +\item + otherwise, if not called during constant evaluation and + \tcode{is_trivially_relocatable_v} is \tcode{true}, then has + effects equivalent to: \tcode{trivially_relocate(first, last, result);} +\item + otherwise, for each integer \tcode{i} in \range{0}{last - first}, + \begin{itemize} + \item + if \tcode{T} is an array type, equivalent to: + \tcode{relocate(begin(first[i]), end(first[i]), *start_lifetime_as(result + i));} + \item + otherwise, equivalent to: + \tcode{construct_at(result + i, std::move(first[i])); destroy_at(first + i);} + \end{itemize} +\end{itemize} + +\pnum +\returns +\tcode{result + (last - first)}. + +\pnum +\throws +Nothing. + +\begin{note} +Overlapping ranges are supported. +\end{note} +\end{itemdescr} + \rSec2[allocator.tag]{Allocator argument tag} \indexlibraryglobal{allocator_arg_t}% @@ -1379,10 +1559,9 @@ template using rebind_alloc = @\seebelow@; template using rebind_traits = allocator_traits>; - [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); - [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, - const_void_pointer hint); - [[nodiscard]] static constexpr allocation_result + static constexpr pointer allocate(Alloc& a, size_type n); + static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); + static constexpr allocation_result allocate_at_least(Alloc& a, size_type n); static constexpr void deallocate(Alloc& a, pointer p, size_type n); @@ -1550,7 +1729,7 @@ \indexlibrarymember{allocate}{allocator_traits}% \begin{itemdecl} -[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); +static constexpr pointer allocate(Alloc& a, size_type n); \end{itemdecl} \begin{itemdescr} @@ -1561,7 +1740,7 @@ \indexlibrarymember{allocate}{allocator_traits}% \begin{itemdecl} -[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); +static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); \end{itemdecl} \begin{itemdescr} @@ -1572,8 +1751,7 @@ \indexlibrarymember{allocate_at_least}{allocator_traits}% \begin{itemdecl} -[[nodiscard]] static constexpr allocation_result - allocate_at_least(Alloc& a, size_type n); +static constexpr allocation_result allocate_at_least(Alloc& a, size_type n); \end{itemdecl} \begin{itemdescr} @@ -1634,7 +1812,7 @@ \pnum \returns \tcode{a.max_size()} if that expression is well-formed; otherwise, -\tcode{numeric_limits::\brk{}max()/sizeof(value_type)}. +\tcode{numeric_limits::\brk{}max() / sizeof(value_type)}. \end{itemdescr} \indexlibrarymember{select_on_container_copy_construction}{allocator_traits}% @@ -1673,7 +1851,7 @@ \begin{codeblock} namespace std { template class allocator { - public: + public: using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; @@ -1685,8 +1863,8 @@ constexpr ~allocator(); constexpr allocator& operator=(const allocator&) = default; - [[nodiscard]] constexpr T* allocate(size_t n); - [[nodiscard]] constexpr allocation_result allocate_at_least(size_t n); + constexpr T* allocate(size_t n); + constexpr allocation_result allocate_at_least(size_t n); constexpr void deallocate(T* p, size_t n); }; } @@ -1707,7 +1885,7 @@ \indexlibrarymember{allocate}{allocator}% \begin{itemdecl} -[[nodiscard]] constexpr T* allocate(size_t n); +constexpr T* allocate(size_t n); \end{itemdecl} \begin{itemdescr} @@ -1737,7 +1915,7 @@ \indexlibrarymember{allocate_at_least}{allocator}% \begin{itemdecl} -[[nodiscard]] constexpr allocation_result allocate_at_least(size_t n); +constexpr allocation_result allocate_at_least(size_t n); \end{itemdecl} \begin{itemdescr} @@ -1935,7 +2113,7 @@ \rSec3[unique.ptr.dltr]{Default deleters} -\rSec4[unique.ptr.dltr.general]{In general} +\rSec4[unique.ptr.dltr.general]{General} \pnum The class template \tcode{default_delete} serves as the default deleter (destruction policy) @@ -2086,6 +2264,14 @@ } \end{codeblock} +\pnum +A program that instantiates the definition of \tcode{unique_ptr} +is ill-formed if \tcode{T*} is an invalid type. +\begin{note} +This prevents the instantiation of specializations such as +\tcode{unique_ptr} and \tcode{unique_ptr}. +\end{note} + \pnum The default type for the template parameter \tcode{D} is \tcode{default_delete}. A client-supplied template argument @@ -2436,9 +2622,13 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{reference_converts_from_temporary_v, decltype(\linebreak{}*declval())>} is \tcode{false}. + \pnum \expects -\tcode{get() != nullptr}. +\tcode{get() != nullptr} is \tcode{true}. \pnum \returns @@ -3275,7 +3465,7 @@ reflect modifications that can introduce data races. \pnum -For the purposes of subclause \ref{smartptr}, +For the purposes of \ref{smartptr}, a pointer type \tcode{Y*} is said to be \defnx{compatible with}{compatible with!\idxcode{shared_ptr}} a pointer type \tcode{T*} when either @@ -3293,10 +3483,10 @@ then \tcode{remove_cv_t*} shall be implicitly convertible to \tcode{T*} and the constructor evaluates the statement: \begin{codeblock} -if (p != nullptr && p->weak_this.expired()) - p->weak_this = shared_ptr>(*this, const_cast*>(p)); +if (p != nullptr && p->@\exposid{weak-this}@.expired()) + p->@\exposid{weak-this}@ = shared_ptr>(*this, const_cast*>(p)); \end{codeblock} -The assignment to the \tcode{weak_this} member is not atomic and +The assignment to the \exposid{weak-this} member is not atomic and conflicts with any potentially concurrent access to the same object\iref{intro.multithread}. \indexlibraryctor{shared_ptr}% @@ -3972,15 +4162,15 @@ \tcode{allocate_shared} shall initialize this (sub)object via the expression \begin{itemize} - \item \tcode{allocator_traits::construct(a2, pv, v)} or - \item \tcode{allocator_traits::construct(a2, pv, l...)} + \item \tcode{allocator_traits::construct(a2, pu, v)} or + \item \tcode{allocator_traits::construct(a2, pu, l...)} \end{itemize} respectively, - where \tcode{pv} points to storage - suitable to hold an object of type \tcode{U} and - \tcode{a2} of type \tcode{A2} is a rebound copy of - the allocator \tcode{a} passed to \tcode{allocate_shared} - such that its \tcode{value_type} is \tcode{remove_cv_t}. + where \tcode{pu} is a pointer of type \tcode{remove_cv_t*} + pointing to storage + suitable to hold an object of type \tcode{remove_cv_t} and + \tcode{a2} of type \tcode{A2} is a potentially rebound copy of + the allocator \tcode{a} passed to \tcode{allocate_shared}. \item When a (sub)object of non-array type \tcode{U} is specified to have a default initial value, @@ -3991,13 +4181,13 @@ \item When a (sub)object of non-array type \tcode{U} is specified to have a default initial value, - \tcode{allocate_shared} shall initialize this (sub)object - via the expression \tcode{allocator_traits::construct(a2, pv)}, - where \tcode{pv} points to storage - suitable to hold an object of type \tcode{U} and - \tcode{a2} of type \tcode{A2} is a rebound copy of - the allocator \tcode{a} passed to \tcode{allocate_shared} - such that its \tcode{value_type} is \tcode{remove_cv_t}. + \tcode{allocate_shared} initializes this (sub)object + via the expression \tcode{allocator_traits::construct(a2, pu)}, + where \tcode{pu} is a pointer of type \tcode{remove_cv_t*} + pointing to storage + suitable to hold an object of type \tcode{remove_cv_t} and + \tcode{a2} of type \tcode{A2} is a potentially rebound copy of + the allocator \tcode{a} passed to \tcode{allocate_shared}. \item When a (sub)object of non-array type \tcode{U} is initialized by \tcode{make_shared_for_overwrite} or\linebreak % avoid Overfull @@ -4014,18 +4204,20 @@ of their original construction. \item When a (sub)object of non-array type \tcode{U} - that was initialized by \tcode{make_shared} is to be destroyed, - it is destroyed via the expression \tcode{pv->\~{}U()} where - \tcode{pv} points to that object of type \tcode{U}. + that was initialized by \tcode{make_shared}, + \tcode{make_shared_for_overwrite}, or \tcode{allocate_shared_for_overwrite} + is to be destroyed, + it is destroyed via the expression \tcode{pu->\~{}U()} where + \tcode{pu} points to that object of type \tcode{U}. \item When a (sub)object of non-array type \tcode{U} that was initialized by \tcode{allocate_shared} is to be destroyed, it is destroyed via the expression - \tcode{allocator_traits::destroy(a2, pv)} where - \tcode{pv} points to that object of type \tcode{remove_cv_t} and - \tcode{a2} of type \tcode{A2} is a rebound copy of - the allocator \tcode{a} passed to \tcode{allocate_shared} - such that its \tcode{value_type} is \tcode{remove_cv_t}. + \tcode{allocator_traits::destroy(a2, pu)} where + \tcode{pu} is a pointer of type \tcode{remove_cv_t*} + pointing to that object of type \tcode{remove_cv_t} and + \tcode{a2} of type \tcode{A2} is a potentially rebound copy of + the allocator \tcode{a} passed to \tcode{allocate_shared}. \end{itemize} \begin{note} These functions will typically allocate more memory than \tcode{sizeof(T)} to @@ -4356,7 +4548,7 @@ \begin{note} The seemingly equivalent expression \tcode{shared_ptr(static_cast(r.get()))} -will eventually result in undefined behavior, attempting to delete the +can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} @@ -4393,7 +4585,7 @@ \pnum \begin{note} The seemingly equivalent expression -\tcode{shared_ptr(dynamic_cast(r.get()))} will eventually result in +\tcode{shared_ptr(dynamic_cast(r.get()))} can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} @@ -4422,7 +4614,7 @@ \pnum \begin{note} The seemingly equivalent expression -\tcode{shared_ptr(const_cast(r.get()))} will eventually result in +\tcode{shared_ptr(const_cast(r.get()))} can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} @@ -4451,7 +4643,7 @@ \pnum \begin{note} The seemingly equivalent expression -\tcode{shared_ptr(reinterpret_cast(r.get()))} will eventually result in +\tcode{shared_ptr(reinterpret_cast(r.get()))} can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} @@ -4988,7 +5180,7 @@ weak_ptr weak_from_this() const noexcept; private: - mutable weak_ptr weak_this; // \expos + mutable weak_ptr @\exposid{weak-this}@; // \expos }; } \end{codeblock} @@ -5006,7 +5198,7 @@ \begin{itemdescr} \pnum \effects -Value-initializes \tcode{weak_this}. +Value-initializes \exposid{weak-this}. \end{itemdescr} \indexlibrarymember{operator=}{enable_shared_from_this}% @@ -5021,7 +5213,7 @@ \pnum \begin{note} -\tcode{weak_this} is not changed. +\exposid{weak-this} is not changed. \end{note} \end{itemdescr} @@ -5035,7 +5227,7 @@ \begin{itemdescr} \pnum \returns -\tcode{shared_ptr(weak_this)}. +\tcode{shared_ptr(\exposid{weak-this})}. \end{itemdescr} \indexlibraryglobal{weak_ptr}% @@ -5048,7 +5240,7 @@ \begin{itemdescr} \pnum \returns -\tcode{weak_this}. +\exposid{weak-this}. \end{itemdescr} \rSec2[util.smartptr.hash]{Smart pointer hash support} @@ -5178,6 +5370,8 @@ Then, equivalent to: \begin{itemize} \item +% pretend to \item that there is real text here, but undo the vertical spacing +\mbox{}\vspace{-\baselineskip}\vspace{-\parskip} \begin{codeblock} s.reset(); \end{codeblock} @@ -5451,10 +5645,8 @@ % pretend to \item that there is real text here, but undo the vertical spacing \mbox{}\vspace{-\baselineskip}\vspace{-\parskip} \begin{codeblock} -if (p) { - apply([&](auto&&... args) { - s = Smart( static_cast(p), std::forward(args)...); }, std::move(a)); -} +apply([&](auto&&... args) { + s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); \end{codeblock} if \tcode{is_pointer_v} is \tcode{true}; \item @@ -5558,190 +5750,1742 @@ \tcode{inout_ptr_t(s, std::forward(args)...)}. \end{itemdescr} -\rSec1[mem.res]{Memory resources} - -\rSec2[mem.res.syn]{Header \tcode{} synopsis} - -\indexheader{memory_resource}% -\begin{codeblock} -namespace std::pmr { - // \ref{mem.res.class}, class \tcode{memory_resource} - class memory_resource; +\rSec1[mem.composite.types]{Types for composite class design} - bool operator==(const memory_resource& a, const memory_resource& b) noexcept; +\rSec2[indirect]{Class template \tcode{indirect}} - // \ref{mem.poly.allocator.class}, class template \tcode{polymorphic_allocator} - template class polymorphic_allocator; +\rSec3[indirect.general]{General} - template - bool operator==(const polymorphic_allocator& a, - const polymorphic_allocator& b) noexcept; +\pnum +An indirect object manages the lifetime of an owned object. +An indirect object is +\defnx{valueless}{valueless!indirect object} if it has no owned object. +An indirect object may become valueless only after it has been moved from. - // \ref{mem.res.global}, global memory resources - memory_resource* new_delete_resource() noexcept; - memory_resource* null_memory_resource() noexcept; - memory_resource* set_default_resource(memory_resource* r) noexcept; - memory_resource* get_default_resource() noexcept; +\pnum +In every specialization \tcode{indirect}, +if the type \tcode{allocator_traits::value_type} +is not the same type as \tcode{T}, +the program is ill-formed. +Every object of type \tcode{indirect} +uses an object of type \tcode{Allocator} to allocate and free storage +for the owned object as needed. + +\pnum +Constructing an owned object with \tcode{args...} +using the allocator \tcode{a} means calling +\tcode{allocator_traits::construct(a, \exposid{p}, args...)} where +\tcode{args} is an expression pack, +\tcode{a} is an allocator, and +\exposid{p} is a pointer obtained by +calling \tcode{allocator_traits::allocate}. + +\pnum +The member \exposid{alloc} is used for +any memory allocation and element construction +performed by member functions +during the lifetime of each indirect object. +The allocator \exposid{alloc} may be replaced +only via assignment or \tcode{swap()}. +\tcode{Allocator} replacement is performed by +copy assignment, +move assignment, or +swapping of the allocator +only if\iref{container.reqmts}: +\begin{itemize} +\item +\tcode{allocator_traits::propagate_on_container_copy_assignment::value}, or +\item +\tcode{allocator_traits::propagate_on_container_move_assignment::value}, or +\item +\tcode{allocator_traits::propagate_on_container_swap::value} +\end{itemize} +is \tcode{true} within the implementation of +the corresponding \tcode{indirect} operation. - // \ref{mem.res.pool}, pool resource classes - struct pool_options; - class synchronized_pool_resource; - class unsynchronized_pool_resource; - class monotonic_buffer_resource; -} -\end{codeblock} +\pnum +A program that instantiates the definition of +the template \tcode{indirect} with +a type for the \tcode{T} parameter that is +a non-object type, +an array type, +\tcode{in_place_t}, +a specialization of \tcode{in_place_type_t}, or +a cv-qualified type +is ill-formed. -\rSec2[mem.res.class]{Class \tcode{memory_resource}} +\pnum +The template parameter \tcode{T} of \tcode{indirect} +may be an incomplete type. -\rSec3[mem.res.class.general]{General} +\pnum +The template parameter \tcode{Allocator} of \tcode{indirect} +shall meet the \oldconcept{Allocator} requirements. \pnum -The \tcode{memory_resource} class is an abstract interface to an unbounded set of classes encapsulating memory resources. +If a program declares an explicit or partial specialization of \tcode{indirect}, +the behavior is undefined. -\indexlibraryglobal{memory_resource}% -\indexlibrarymember{operator=}{memory_resource}% -\begin{codeblock} -namespace std::pmr { - class memory_resource { - static constexpr size_t max_align = alignof(max_align_t); // \expos +\rSec3[indirect.syn]{Synopsis} +\indexlibraryglobal{indirect}% +\begin{codeblock} +namespace std { + template> + class indirect { public: - memory_resource() = default; - memory_resource(const memory_resource&) = default; - virtual ~memory_resource(); - - memory_resource& operator=(const memory_resource&) = default; - - [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align); - void deallocate(void* p, size_t bytes, size_t alignment = max_align); - - bool is_equal(const memory_resource& other) const noexcept; + using value_type = T; + using allocator_type = Allocator; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; + + // \ref{indirect.ctor}, constructors + constexpr explicit indirect(); + constexpr explicit indirect(allocator_arg_t, const Allocator& a); + constexpr indirect(const indirect& other); + constexpr indirect(allocator_arg_t, const Allocator& a, const indirect& other); + constexpr indirect(indirect&& other) noexcept; + constexpr indirect(allocator_arg_t, const Allocator& a, indirect&& other) + noexcept(@\seebelow@); + template + constexpr explicit indirect(U&& u); + template + constexpr explicit indirect(allocator_arg_t, const Allocator& a, U&& u); + template + constexpr explicit indirect(in_place_t, Us&&... us); + template + constexpr explicit indirect(allocator_arg_t, const Allocator& a, + in_place_t, Us&&... us); + template + constexpr explicit indirect(in_place_t, initializer_list ilist, Us&&... us); + template + constexpr explicit indirect(allocator_arg_t, const Allocator& a, + in_place_t, initializer_list ilist, Us&&... us); + + // \ref{indirect.dtor}, destructor + constexpr ~indirect(); + + // \ref{indirect.asgn}, assignment + constexpr indirect& operator=(const indirect& other); + constexpr indirect& operator=(indirect&& other) noexcept(@\seebelow@); + template + constexpr indirect& operator=(U&& u); + + // \ref{indirect.obs}, observers + constexpr const T& operator*() const & noexcept; + constexpr T& operator*() & noexcept; + constexpr const T&& operator*() const && noexcept; + constexpr T&& operator*() && noexcept; + constexpr const_pointer operator->() const noexcept; + constexpr pointer operator->() noexcept; + constexpr bool valueless_after_move() const noexcept; + constexpr allocator_type get_allocator() const noexcept; + + // \ref{indirect.swap}, swap + constexpr void swap(indirect& other) noexcept(@\seebelow@); + friend constexpr void swap(indirect& lhs, indirect& rhs) noexcept(@\seebelow@); + + // \ref{indirect.relops}, relational operators + template + friend constexpr bool operator==(const indirect& lhs, const indirect& rhs) + noexcept(@\seebelow@); + template + friend constexpr auto operator<=>(const indirect& lhs, const indirect& rhs) + -> @\exposid{synth-three-way-result}@; + + // \ref{indirect.comp.with.t}, comparison with \tcode{T} + template + friend constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(@\seebelow@); + template + friend constexpr auto operator<=>(const indirect& lhs, const U& rhs) + -> @\exposid{synth-three-way-result}@; private: - virtual void* do_allocate(size_t bytes, size_t alignment) = 0; - virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; - - virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; + pointer @\exposid{p}@; // \expos + Allocator @\exposid{alloc}@ = Allocator(); // \expos }; + template + indirect(Value) -> indirect; + template + indirect(allocator_arg_t, Allocator, Value) + -> indirect::template rebind_alloc>; } \end{codeblock} +\rSec3[indirect.ctor]{Constructors} -\rSec3[mem.res.public]{Public member functions} - -\indexlibrarydtor{memory_resource}% -\begin{itemdecl} -~memory_resource(); -\end{itemdecl} +\pnum +The following element applies to all functions in~\ref{indirect.ctor}: \begin{itemdescr} \pnum -\effects -Destroys this \tcode{memory_resource}. +\throws +Nothing unless \tcode{allocator_traits::allocate} or +\tcode{allocator_traits::construct} throws. \end{itemdescr} -\indexlibrarymember{allocate}{memory_resource}% +\indexlibraryctor{indirect}% \begin{itemdecl} -[[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align); +constexpr explicit indirect(); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Allocates storage by calling \tcode{do_allocate(bytes, alignment)} and -implicitly creates objects within the allocated region of storage. +\constraints +\tcode{is_default_constructible_v} is \tcode{true}. \pnum -\returns -A pointer to a suitable created object\iref{intro.object} -in the allocated region of storage. +\mandates +\tcode{is_default_constructible_v} is \tcode{true}. \pnum -\throws -What and when the call to \tcode{do_allocate} throws. +\effects +Constructs an owned object of type \tcode{T} with an empty argument list, +using the allocator \exposid{alloc}. \end{itemdescr} -\indexlibrarymember{deallocate}{memory_resource}% +\indexlibraryctor{indirect}% \begin{itemdecl} -void deallocate(void* p, size_t bytes, size_t alignment = max_align); +constexpr explicit indirect(allocator_arg_t, const Allocator& a); \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{is_default_constructible_v} is \tcode{true}. + \pnum \effects -Equivalent to \tcode{do_deallocate(p, bytes, alignment)}. +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{T} with an empty argument list, +using the allocator \exposid{alloc}. \end{itemdescr} -\indexlibrarymember{is_equal}{memory_resource}% +\indexlibraryctor{indirect}% \begin{itemdecl} -bool is_equal(const memory_resource& other) const noexcept; +constexpr indirect(const indirect& other); \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{is_copy_constructible_v} is \tcode{true}. + \pnum \effects -Equivalent to: \tcode{return do_is_equal(other);} +\exposid{alloc} is direct-non-list-initialized with +\tcode{allocator_traits::select_on_contai\-ner_copy_construction(other.\exposid{alloc})}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise, +constructs an owned object of type \tcode{T} with \tcode{*other}, +using the allocator \exposid{alloc}. \end{itemdescr} - -\rSec3[mem.res.private]{Private virtual member functions} - -\indexlibrarymember{do_allocate}{memory_resource}% +\indexlibraryctor{indirect}% \begin{itemdecl} -virtual void* do_allocate(size_t bytes, size_t alignment) = 0; +constexpr indirect(allocator_arg_t, const Allocator& a, const indirect& other); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{alignment} is a power of two. - -\pnum -\returns -A derived class shall implement this function to -return a pointer to allocated storage\iref{basic.stc.dynamic.allocation} -with a size of at least \tcode{bytes}, -aligned to the specified \tcode{alignment}. +\mandates +\tcode{is_copy_constructible_v} is \tcode{true}. \pnum -\throws -A derived class implementation shall throw an appropriate exception if it is unable to allocate memory with the requested size and alignment. +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise, +constructs an owned object of type \tcode{T} with \tcode{*other}, +using the allocator \exposid{alloc}. \end{itemdescr} -\indexlibrarymember{do_deallocate}{memory_resource}% +\indexlibraryctor{indirect}% \begin{itemdecl} -virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; +constexpr indirect(indirect&& other) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{p} was returned from a prior call to \tcode{allocate(bytes, alignment)} -on a memory resource equal to \tcode{*this}, -and the storage at \tcode{p} has not yet been deallocated. - \pnum \effects -A derived class shall implement this function to dispose of allocated storage. +\exposid{alloc} is direct-non-list-initialized from +\tcode{std::move(other.\exposid{alloc})}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise \tcode{*this} takes ownership of the owned object of \tcode{other}. \pnum -\throws -Nothing. +\ensures +\tcode{other} is valueless. \end{itemdescr} -\indexlibrarymember{do_is_equal}{memory_resource}% +\indexlibraryctor{indirect}% \begin{itemdecl} -virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; +constexpr indirect(allocator_arg_t, const Allocator& a, indirect&& other) + noexcept(allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum -\returns -A derived class shall implement this function to return \tcode{true} if memory allocated from \keyword{this} can be deallocated from \tcode{other} and vice-versa, -otherwise \tcode{false}. -\begin{note} -It is possible that the most-derived type of \tcode{other} does not match the type of \keyword{this}. -For a derived class \tcode{D}, an implementation of this function +\mandates +If \tcode{allocator_traits::is_always_equal::value} is \tcode{false} +then \tcode{T} is a complete type. + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise, +if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, +constructs an object of type \tcode{indirect} that +takes ownership of the owned object of \tcode{other}. +Otherwise, +constructs an owned object of type \tcode{T} with \tcode{*std::move(other)}, +using the allocator \exposid{alloc}. + +\pnum +\ensures +\tcode{other} is valueless. +\end{itemdescr} + +\indexlibraryctor{indirect}% +\begin{itemdecl} +template + constexpr explicit indirect(U&& u); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, indirect>} is \tcode{false}, +\item +\tcode{is_same_v, in_place_t>} is \tcode{false}, +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Constructs an owned object of type \tcode{T} with \tcode{std::forward(u)}, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{indirect}% +\begin{itemdecl} +template + constexpr explicit indirect(allocator_arg_t, const Allocator& a, U&& u); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, indirect>} is \tcode{false}, +\item +\tcode{is_same_v, in_place_t>} is \tcode{false}, and +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{T} with +\tcode{std::forward(u)}, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{indirect}% +\begin{itemdecl} +template + constexpr explicit indirect(in_place_t, Us&&... us); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Constructs an owned object of type \tcode{T} with +\tcode{std::forward(us)...}, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{indirect}% +\begin{itemdecl} +template + constexpr explicit indirect(allocator_arg_t, const Allocator& a, + in_place_t, Us&& ...us); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{T} with +\tcode{std::forward(us)...}, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{indirect}% +\begin{itemdecl} +template + constexpr explicit indirect(in_place_t, initializer_list ilist, Us&&... us); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v\&, Us...>} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Constructs an owned object of type \tcode{T} with the arguments +\tcode{ilist, std::forward(us)...}, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{indirect}% +\begin{itemdecl} +template + constexpr explicit indirect(allocator_arg_t, const Allocator& a, + in_place_t, initializer_list ilist, Us&&... us); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v\&, Us...>} is \tcode{true}. + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{T} with the arguments +\tcode{ilist, std::forward(us)...}, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\rSec3[indirect.dtor]{Destructor} + +\indexlibrarydtor{indirect}% +\begin{itemdecl} +constexpr ~indirect(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a complete type. + +\pnum +\effects +If \tcode{*this} is not valueless, +destroys the owned object +using \tcode{allocator_traits::de\-stroy} and +then the storage is deallocated. +\end{itemdescr} + +\rSec3[indirect.asgn]{Assignment} + +\indexlibrarymember{operator=}{indirect}% +\begin{itemdecl} +constexpr indirect& operator=(const indirect& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates + +\begin{itemize} +\item +\tcode{is_copy_assignable_v} is \tcode{true}, and +\item +\tcode{is_copy_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. +Otherwise: + +\begin{itemize} +\item +%FIXME: We're defining what it means for an allocator to "need updating" here? +%FIXME: (Note: that this concept is used elsewhere so it must be defined)... +%FIXME: How is this an "effect"? +The allocator needs updating if +\tcode{allocator_traits::propagate_on_container_copy_assignment::value} +is \tcode{true}. + +\item +If \tcode{other} is valueless, +\tcode{*this} becomes valueless and +the owned object in \tcode{*this}, if any, +is destroyed using \tcode{allocator_traits::destroy} and +then the storage is deallocated. + +\item +Otherwise, +if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true} and +\tcode{*this} is not valueless, +equivalent to \tcode{**this = *other}. + +\item +Otherwise a new owned object is constructed in \tcode{*this} +using \tcode{allocator_traits::con\linebreak{}struct} with +the owned object from \tcode{other} as the argument, +using either the allocator in \tcode{*this} or +%FIXME: Concept "allocator needs updating" not defined/referenced. +%FIXME: Same for all usages below. +the allocator in \tcode{other} if the allocator needs updating. + +\item +The previously owned object in \tcode{*this}, if any, +is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and +then the storage is deallocated. + +\item +If the allocator needs updating, +the allocator in \tcode{*this} is replaced with +a copy of the allocator in \tcode{other}. +\end{itemize} + +\pnum +\returns +A reference to \tcode{*this}. + +\pnum +\remarks +If any exception is thrown, +the result of the expression \tcode{this->valueless_after_move()} +remains unchanged. +If an exception is thrown during +the call to \tcode{T}{'s} selected copy constructor, no effect. +If an exception is thrown during the call to \tcode{T}{'s} copy assignment, +the state of its contained value +is as defined by the exception safety guarantee of +\tcode{T}{'s} copy assignment. +\end{itemdescr} + +\indexlibrarymember{operator=}{indirect}% +\begin{itemdecl} +constexpr indirect& operator=(indirect&& other) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_copy_constructible_t} is \tcode{true}. + +\pnum +\effects +If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. +Otherwise: + +\begin{itemize} +\item +%FIXME: We're defining "allocator needs updating" as an effect? +%FIXME: (Same issue as above) +The allocator needs updating if +\tcode{allocator_traits::propagate_on_container_move_assignment::value} +is \tcode{true}. + +\item +If \tcode{other} is valueless, +\tcode{*this} becomes valueless and +the owned object in \tcode{*this}, if any, +is destroyed using \tcode{allocator_traits::destroy} and +then the storage is deallocated. + +\item +Otherwise, +if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, +swaps the owned objects in \tcode{*this} and \tcode{other}; +the owned object in \tcode{other}, if any, +is then destroyed using \tcode{allocator_traits::destroy} and +then the storage is deallocated. + +\item +Otherwise, +constructs a new owned object with +%FIXME: "as the argument as an rvalue" is awkward. +the owned object of \tcode{other} as the argument as an rvalue, +using either +the allocator in \tcode{*this} or +the allocator in \tcode{other} +if the allocator needs updating. + +\item +The previously owned object in \tcode{*this}, if any, +is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and +then the storage is deallocated. + +\item +If the allocator needs updating, +the allocator in \tcode{*this} is replaced with +a copy of the allocator in \tcode{other}. +\end{itemize} + +\pnum +\ensures +\tcode{other} is valueless. + +\pnum +\returns +A reference to \tcode{*this}. + +\pnum +\remarks +If any exception is thrown, +there are no effects on \tcode{*this} or \tcode{other}. +\end{itemdescr} + +\indexlibrarymember{operator=}{indirect}% +\begin{itemdecl} +template + constexpr indirect& operator=(U&& u); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, indirect>} is \tcode{false}, +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{is_assignable_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +If \tcode{*this} is valueless then +constructs an owned object of type \tcode{T} with \tcode{std::forward(u)} +using the allocator \exposid{alloc}. +Otherwise, +equivalent to \tcode{**this = std::forward(u)}. + +\pnum +\returns +A reference to \tcode{*this}. +\end{itemdescr} + +\rSec3[indirect.obs]{Observers} + +\indexlibrarymember{operator*}{indirect}% +\begin{itemdecl} +constexpr const T& operator*() const & noexcept; +constexpr T& operator*() & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{*this} is not valueless. + +\pnum +\returns +\tcode{*\exposid{p}}. +\end{itemdescr} + +\indexlibrarymember{operator*}{indirect}% +\begin{itemdecl} +constexpr const T&& operator*() const && noexcept; +constexpr T&& operator*() && noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{*this} is not valueless. + +\pnum +\returns +\tcode{std::move(*\exposid{p})}. +\end{itemdescr} + +\indexlibrarymember{operator->}{indirect}% +\begin{itemdecl} +constexpr const_pointer operator->() const noexcept; +constexpr pointer operator->() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{*this} is not valueless. + +\pnum +\returns +\exposid{p}. +\end{itemdescr} + +\indexlibrarymember{valueless_after_move}{indirect}% +\begin{itemdecl} +constexpr bool valueless_after_move() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{*this} is valueless, otherwise \tcode{false}. +\end{itemdescr} + +\indexlibrarymember{get_allocator}{indirect}% +\begin{itemdecl} +constexpr allocator_type get_allocator() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{alloc}. +\end{itemdescr} + +\rSec3[indirect.swap]{Swap} + +\indexlibrarymember{swap}{indirect}% +\begin{itemdecl} +constexpr void swap(indirect& other) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +If +\tcode{allocator_traits::propagate_on_container_swap::value} +is \tcode{true}, then +\tcode{Allocator} meets the \oldconcept{Swappable} requirements. +Otherwise \tcode{get_allocator() == other.\linebreak{}get_allocator()} is \tcode{true}. + +\pnum +\effects +Swaps the states of \tcode{*this} and \tcode{other}, +exchanging owned objects or valueless states. +If \tcode{allocator_traits::propagate_on_container_swap::value} +is \tcode{true}, +then the allocators of \tcode{*this} and \tcode{other} +are exchanged by calling \tcode{swap} as described in~\ref{swappable.requirements}. +Otherwise, +the allocators are not swapped. +\begin{note} +Does not call \tcode{swap} on the owned objects directly. +\end{note} +\end{itemdescr} + +\indexlibrarymember{swap}{indirect}% +%FIXME: "friend" included on declaration in synopsis but not here. +\begin{itemdecl} +constexpr void swap(indirect& lhs, indirect& rhs) noexcept(noexcept(lhs.swap(rhs))); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{lhs.swap(rhs)}. +\end{itemdescr} + +\rSec3[indirect.relops]{Relational operators} + +\indexlibrarymember{operator==}{indirect}% +%FIXME: "friend" included on declaration in synopsis but not here. +\begin{itemdecl} +template + constexpr bool operator==(const indirect& lhs, const indirect& rhs) + noexcept(noexcept(*lhs == *rhs)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{*lhs == *rhs} is well-formed and +its result is convertible to \tcode{bool}. + +\pnum +\returns +If \tcode{lhs} is valueless or \tcode{rhs} is valueless, +\tcode{lhs.valueless_after_move() == rhs.valueless_after_move()}; +otherwise \tcode{*lhs == *rhs}. +\end{itemdescr} + +\indexlibrarymember{\exposid{synth-three-way-result}}{indirect}% +%FIXME: "friend" included on declaration in synopsis but not here. +\begin{itemdecl} +template + constexpr @\exposid{synth-three-way-result}@ + operator<=>(const indirect& lhs, const indirect& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{lhs} is valueless or \tcode{rhs} is valueless, +\tcode{!lhs.valueless_after_move() <=> !rhs.value\-less_after_move()}; +otherwise +\tcode{\exposid{synth-three-way}(*lhs, *rhs)}. +\end{itemdescr} + +\rSec3[indirect.comp.with.t]{Comparison with \tcode{T}} + +\indexlibrarymember{operator==}{indirect}% +%FIXME: "friend" included on declaration in synopsis but not here. +\begin{itemdecl} +template + constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(noexcept(*lhs == rhs)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{*lhs == rhs} is well-formed and +its result is convertible to \tcode{bool}. + +\pnum +\returns +If \tcode{lhs} is valueless, \tcode{false}; +otherwise \tcode{*lhs == rhs}. +\end{itemdescr} + +\indexlibrarymember{\exposid{synth-three-way-result}}{indirect}% +%FIXME: "friend" included on declaration in synopsis but not here. +\begin{itemdecl} +template + constexpr @\exposid{synth-three-way-result}@ + operator<=>(const indirect& lhs, const U& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{lhs} is valueless, \tcode{strong_ordering::less}; +otherwise \tcode{\exposid{synth-three-way}(*lhs, rhs)}. +\end{itemdescr} + +\rSec3[indirect.hash]{Hash support} + +\indexlibrarymember{hash}{indirect}% +\begin{itemdecl} +template +struct hash>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The specialization \tcode{hash>} +is enabled\iref{unord.hash} if and only if \tcode{hash} is enabled. +When enabled for an object \tcode{i} of type \tcode{indirect}, +%FIXME: Cleanup wording/punctuation and make consistent. +\tcode{hash>()(i)} evaluates to +either the same value as \tcode{hash()(*i)}, +if \tcode{i} is not valueless; +otherwise to an +\impldef{result of evaluating \tcode{hash>()(i)} if \tcode{i} is valueless} +value. +The member functions are not guaranteed to be \tcode{noexcept}. +\end{itemdescr} + +\rSec2[polymorphic]{Class template \tcode{polymorphic}} + +\rSec3[polymorphic.general]{General} + +\pnum +A polymorphic object manages the lifetime of an owned object. +A polymorphic object may own objects of +different types at different points in its lifetime. +A polymorphic object is +\defnx{valueless}{valueless!polymorphic object} +if it has no owned object. +A polymorphic object may become valueless only after it has been moved from. + +\pnum +In every specialization \tcode{polymorphic}, +if the type \tcode{allocator_traits::value_type} +is not the same type as \tcode{T}, the program is ill-formed. +Every object of type \tcode{polymorphic} +uses an object of type \tcode{Allocator} to +allocate and free storage for the owned object as needed. + +\pnum +Constructing an owned object of type \tcode{U} with \tcode{args...} +using the allocator \tcode{a} means calling +\tcode{allocator_traits::construct(a, \exposid{p}, args...)} where +\tcode{args} is an expression pack, +\tcode{a} is an allocator, and +\exposid{p} points to storage suitable for an owned object of type \tcode{U}. + +\pnum +The member \exposid{alloc} is used for +any memory allocation and element construction +performed by member functions +during the lifetime of each polymorphic value object, or +until the allocator is replaced. +The allocator may be replaced only via +assignment or \tcode{swap()}. +\tcode{Allocator} replacement is performed by +copy assignment, +move assignment, or +swapping of the allocator +only if\iref{container.reqmts}: +\begin{itemize} +\item +\tcode{allocator_traits::propagate_on_container_copy_assignment::value}, or +\item +\tcode{allocator_traits::propagate_on_container_move_assignment::value}, or +\item +\tcode{allocator_traits::propagate_on_container_swap::value} +\end{itemize} +is \tcode{true} within the implementation of +the corresponding \tcode{polymorphic} operation. + +\pnum +A program that instantiates the definition of \tcode{polymorphic} for +a non-object type, +an array type, +\tcode{in_place_t}, +a specialization of \tcode{in_place_type_t}, or +a cv-qualified type +is ill-formed. + +\pnum +The template parameter \tcode{T} of \tcode{polymorphic} +may be an incomplete type. + +\pnum +The template parameter \tcode{Allocator} of \tcode{polymorphic} +shall meet the requirements of \oldconcept{Allocator}. + +\pnum +If a program declares an explicit or +partial specialization of \tcode{polymorphic}, +the behavior is undefined. + +\rSec3[polymorphic.syn]{Synopsis} + +\indexlibraryglobal{polymorphic}% +\begin{codeblock} +namespace std { + template> + class polymorphic { + public: + using value_type = T; + using allocator_type = Allocator; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; + + // \ref{polymorphic.ctor}, constructors + constexpr explicit polymorphic(); + constexpr explicit polymorphic(allocator_arg_t, const Allocator& a); + constexpr polymorphic(const polymorphic& other); + constexpr polymorphic(allocator_arg_t, const Allocator& a, const polymorphic& other); + constexpr polymorphic(polymorphic&& other) noexcept; + constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other) + noexcept(@\seebelow@); + template + constexpr explicit polymorphic(U&& u); + template + constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, U&& u); + template + constexpr explicit polymorphic(in_place_type_t, Ts&&... ts); + template + constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, + in_place_type_t, Ts&&... ts); + template + constexpr explicit polymorphic(in_place_type_t, initializer_list ilist, Us&&... us); + template + constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, + in_place_type_t, initializer_list ilist, Us&&... us); + + // \ref{polymorphic.dtor}, destructor + constexpr ~polymorphic(); + + // \ref{polymorphic.asgn}, assignment + constexpr polymorphic& operator=(const polymorphic& other); + constexpr polymorphic& operator=(polymorphic&& other) noexcept(@\seebelow@); + + // \ref{polymorphic.obs}, observers + constexpr const T& operator*() const noexcept; + constexpr T& operator*() noexcept; + constexpr const_pointer operator->() const noexcept; + constexpr pointer operator->() noexcept; + constexpr bool valueless_after_move() const noexcept; + constexpr allocator_type get_allocator() const noexcept; + + // \ref{polymorphic.swap}, swap + constexpr void swap(polymorphic& other) noexcept(@\seebelow@); + friend constexpr void swap(polymorphic& lhs, polymorphic& rhs) noexcept(@\seebelow@); + + private: + Allocator @\exposid{alloc}@ = Allocator(); // \expos + }; +} +\end{codeblock} + +\rSec3[polymorphic.ctor]{Constructors} + +\pnum +The following element applies to all functions in~\ref{polymorphic.ctor}: + +\begin{itemdescr} +\pnum +\throws +Nothing unless \tcode{allocator_traits::allocate} or +\tcode{allocator_traits::construct} throws. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +constexpr explicit polymorphic(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_default_constructible_v} is \tcode{true}. + +\pnum +\mandates +\begin{itemize} +\item +\tcode{is_default_constructible_v} is \tcode{true}, and +\item +\tcode{is_copy_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Constructs an owned object of type \tcode{T} with an empty argument list +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{indirect}% +\begin{itemdecl} +constexpr explicit polymorphic(allocator_arg_t, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\begin{itemize} +\item +\tcode{is_default_constructible_v} is \tcode{true}, and +\item +\tcode{is_copy_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{T} with an empty argument list +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +constexpr polymorphic(const polymorphic& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with +\tcode{allocator_traits::select_on_contai\-ner_copy_construction(other.\exposid{alloc})}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise, +constructs an owned object of type \tcode{U}, where +\tcode{U} is the type of the owned object in \tcode{other}, with +the owned object in \tcode{other} using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +constexpr polymorphic(allocator_arg_t, const Allocator& a, const polymorphic& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise, +constructs an owned object of type \tcode{U}, where +\tcode{U} is the type of the owned object in \tcode{other}, with +the owned object in \tcode{other} using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +constexpr polymorphic(polymorphic&& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with +\tcode{std::move(other.\exposid{alloc})}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise, +either \tcode{*this} +takes ownership of the owned object of \tcode{other} or, +%FIXME: Cleanup awkward wording. +owns an object of the same type +constructed from the owned object of \tcode{other} +considering that owned object as an rvalue, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other) + noexcept(allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +If \tcode{other} is valueless, \tcode{*this} is valueless. +Otherwise, +if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, +either constructs an object of type \tcode{polymorphic} that +owns the owned object of \tcode{other}, +making \tcode{other} valueless; or, +%FIXME: Cleanup awkward wording. (And similar wording elsewhere). +owns an object of the same type constructed from +the owned object of \tcode{other} +considering that owned object as an rvalue. +Otherwise, +if \tcode{\exposid{alloc} != other.\exposid{alloc}} is \tcode{true}, +constructs an object of type \tcode{polymorphic}, +considering the owned object in \tcode{other} as an rvalue, +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +template + constexpr explicit polymorphic(U&& u); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +Where \tcode{UU} is \tcode{remove_cvref_t}, +\begin{itemize} +\item +\tcode{is_same_v} is \tcode{false}, +\item +\tcode{derived_from} is \tcode{true}, +\item +\tcode{is_constructible_v} is \tcode{true}, +\item +\tcode{is_copy_constructible_v} is \tcode{true}, +\item +\tcode{UU} is not a specialization of \tcode{in_place_type_t}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Constructs an owned object of type \tcode{U} with \tcode{std::forward(u)} +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +template + constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, U&& u); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +Where \tcode{UU} is \tcode{remove_cvref_t}, +\begin{itemize} +\item +\tcode{is_same_v} is \tcode{false}, +\item +\tcode{derived_from} is \tcode{true}, +\item +\tcode{is_constructible_v} is \tcode{true}, +\item +\tcode{is_copy_constructible_v} is \tcode{true}, and +\item +\tcode{UU} is not a specialization of \tcode{in_place_type_t}. +\end{itemize} + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{U} with \tcode{std::forward(u)} +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +template + constexpr explicit polymorphic(in_place_type_t, Ts&&... ts); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, U>} is \tcode{true}, +\item +\tcode{derived_from} is \tcode{true}, +\item +\tcode{is_constructible_v} is \tcode{true}, +\item +\tcode{is_copy_constructible_v} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Constructs an owned object of type \tcode{U} with +\tcode{std::forward(ts)...} +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +template + constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, + in_place_type_t, Ts&&... ts); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, U>} is \tcode{true}, +\item +\tcode{derived_from} is \tcode{true}, +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{is_copy_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{U} with +\tcode{std::forward(ts)...} +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +template + constexpr explicit polymorphic(in_place_type_t, initializer_list ilist, Us&&... us); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, U>} is \tcode{true}, +\item +\tcode{derived_from} is \tcode{true}, +\item +\tcode{is_constructible_v\&, Us...>} is \tcode{true}, +\item +\tcode{is_copy_constructible_v} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Constructs an owned object of type \tcode{U} with +the arguments \tcode{ilist, std::forward(us)...} +using the allocator \exposid{alloc}. +\end{itemdescr} + +\indexlibraryctor{polymorphic}% +\begin{itemdecl} +template + constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, + in_place_type_t, initializer_list ilist, Us&&... us); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints + +\begin{itemize} +\item +\tcode{is_same_v, U>} is \tcode{true}, +\item +\tcode{derived_from} is \tcode{true}, +\item +\tcode{is_constructible_v\&, Us...>} is \tcode{true}, and +\item +\tcode{is_copy_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\effects +\exposid{alloc} is direct-non-list-initialized with \tcode{a}. +Constructs an owned object of type \tcode{U} with the arguments +\tcode{ilist, std::forward(us)...} +using the allocator \exposid{alloc}. +\end{itemdescr} + +\rSec3[polymorphic.dtor]{Destructor} + +\indexlibrarydtor{polymorphic}% +\begin{itemdecl} +constexpr ~polymorphic(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a complete type. + +\pnum +\effects +If \tcode{*this} is not valueless, +destroys the owned object using \tcode{allocator_traits::de\-stroy} and +then the storage is deallocated. +\end{itemdescr} + +\rSec3[polymorphic.asgn]{Assignment} + +\indexlibrarymember{operator=}{polymorphic}% +\indexlibrarydtor{polymorphic}% +\begin{itemdecl} +constexpr polymorphic& operator=(const polymorphic& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a complete type. + +\pnum +\effects +If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. +Otherwise: + +\begin{itemize} +\item +%FIXME: We're defining "allocator needs updating" as an effect? +%FIXME: (Same issue as above) +The allocator needs updating if +\tcode{allocator_traits::propagate_on_contai\-ner_copy_assignment::value} +is \tcode{true}. + +\item +If \tcode{other} is not valueless, +a new owned object is constructed in \tcode{*this} using +\tcode{allocator_traits::construct} with +the owned object from \tcode{other} as the argument, using either +the allocator in \tcode{*this} or +the allocator in \tcode{other} if the allocator needs updating. + +\item +The previously owned object in \tcode{*this}, if any, +is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and +then the storage is deallocated. + +\item +If the allocator needs updating, +the allocator in \tcode{*this} is replaced with +a copy of the allocator in \tcode{other}. +\end{itemize} + +\pnum +\returns +A reference to \tcode{*this}. + +\pnum +\remarks +If any exception is thrown, there are no effects on \tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{polymorphic}% +\begin{itemdecl} +constexpr polymorphic& operator=(polymorphic&& other) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +If \tcode{allocator_traits::is_always_equal::value} is \tcode{false}, +\tcode{T} is a complete type. + +\pnum +\effects +If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. +Otherwise: + +\begin{itemize} +\item +%FIXME: We're defining "allocator needs updating" as an effect? +%FIXME: (Same issue as above) +The allocator needs updating if +\tcode{allocator_traits::propagate_on_container_move_assignment::value} +is \tcode{true}. + +\item +If \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, +swaps the owned objects in \tcode{*this} and \tcode{other}; +the owned object in \tcode{other}, if any, +is then destroyed using \tcode{allocator_traits::destroy} and +then the storage is deallocated. + +\item +Otherwise, +if \tcode{\exposid{alloc} != other.\exposid{alloc}} is \tcode{true}; +if \tcode{other} is not valueless, +a new owned object is constructed in \tcode{*this} +using \tcode{allocator_traits::construct} with +%FIXME: Cleanup wording. +the owned object from \tcode{other} as the argument as an rvalue, +using either the allocator in \tcode{*this} or +the allocator in \tcode{other} if the allocator needs updating. + +\item +The previously owned object in \tcode{*this}, if any, +is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and +then the storage is deallocated. + +\item +If the allocator needs updating, +the allocator in \tcode{*this} is replaced with +a copy of the allocator in \tcode{other}. +\end{itemize} + +\pnum +\returns +A reference to \tcode{*this}. + +\pnum +\remarks +If any exception is thrown, +there are no effects on \tcode{*this} or \tcode{other}. +\end{itemdescr} + +\rSec3[polymorphic.obs]{Observers} + +\indexlibrarymember{operator*}{polymorphic}% +\begin{itemdecl} +constexpr const T& operator*() const noexcept; +constexpr T& operator*() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{*this} is not valueless. + +\pnum +\returns +A reference to the owned object. +\end{itemdescr} + +\indexlibrarymember{operator->}{polymorphic}% +\begin{itemdecl} +constexpr const_pointer operator->() const noexcept; +constexpr pointer operator->() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{*this} is not valueless. + +\pnum +\returns +A pointer to the owned object. +\end{itemdescr} + +\indexlibrarymember{valueless_after_move}{polymorphic}% +\begin{itemdecl} +constexpr bool valueless_after_move() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{*this} is valueless, otherwise \tcode{false}. +\end{itemdescr} + +\indexlibrarymember{get_allocator}{polymorphic}% +\begin{itemdecl} +constexpr allocator_type get_allocator() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\exposid{alloc}. +\end{itemdescr} + +\rSec3[polymorphic.swap]{Swap} + +\indexlibrarymember{swap}{polymorphic}% +\begin{itemdecl} +constexpr void swap(polymorphic& other) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +If \tcode{allocator_traits::propagate_on_container_swap::value} +is \tcode{true}, then +\tcode{Allocator} meets the \oldconcept{Swappable} requirements. +Otherwise \tcode{get_allocator() == other.\linebreak{}get_allocator()} is \tcode{true}. + +\pnum +\effects +Swaps the states of \tcode{*this} and \tcode{other}, +exchanging owned objects or valueless states. +If \tcode{allocator_traits::propagate_on_container_swap::value} +is \tcode{true}, then +the allocators of \tcode{*this} and \tcode{other} +are exchanged by calling \tcode{swap} +as described in~\ref{swappable.requirements}. +Otherwise, +the allocators are not swapped. +\begin{note} +Does not call \tcode{swap} on the owned objects directly. +\end{note} +\end{itemdescr} + +\indexlibrarymember{swap}{polymorphic}% +%FIXME: "friend" included on declaration in synopsis but not here. +\begin{itemdecl} +constexpr void swap(polymorphic& lhs, polymorphic& rhs) noexcept(noexcept(lhs.swap(rhs))); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{lhs.swap(rhs)}. +\end{itemdescr} + +\rSec1[mem.res]{Memory resources} + +\rSec2[mem.res.syn]{Header \tcode{} synopsis} + +\indexheader{memory_resource}% +\begin{codeblock} +namespace std::pmr { + // \ref{mem.res.class}, class \tcode{memory_resource} + class memory_resource; + + 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; + + 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; + memory_resource* null_memory_resource() noexcept; + memory_resource* set_default_resource(memory_resource* r) noexcept; + memory_resource* get_default_resource() noexcept; + + // \ref{mem.res.pool}, pool resource classes + struct pool_options; + class synchronized_pool_resource; + class unsynchronized_pool_resource; + class monotonic_buffer_resource; +} +\end{codeblock} + +\rSec2[mem.res.class]{Class \tcode{memory_resource}} + +\rSec3[mem.res.class.general]{General} + +\pnum +The \tcode{memory_resource} class is an abstract interface to an unbounded set of classes encapsulating memory resources. + +\indexlibraryglobal{memory_resource}% +\indexlibrarymember{operator=}{memory_resource}% +\begin{codeblock} +namespace std::pmr { + class memory_resource { + static constexpr size_t max_align = alignof(max_align_t); // \expos + + public: + memory_resource() = default; + memory_resource(const memory_resource&) = default; + virtual ~memory_resource(); + + memory_resource& operator=(const memory_resource&) = default; + + void* allocate(size_t bytes, size_t alignment = max_align); + void deallocate(void* p, size_t bytes, size_t alignment = max_align); + + bool is_equal(const memory_resource& other) const noexcept; + + private: + virtual void* do_allocate(size_t bytes, size_t alignment) = 0; + virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; + + virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; + }; +} +\end{codeblock} + + +\rSec3[mem.res.public]{Public member functions} + +\indexlibrarydtor{memory_resource}% +\begin{itemdecl} +~memory_resource(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Destroys this \tcode{memory_resource}. +\end{itemdescr} + +\indexlibrarymember{allocate}{memory_resource}% +\begin{itemdecl} +void* allocate(size_t bytes, size_t alignment = max_align); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Allocates storage by calling \tcode{do_allocate(bytes, alignment)} and +implicitly creates objects within the allocated region of storage. + +\pnum +\returns +A pointer to a suitable created object\iref{intro.object} +in the allocated region of storage. + +\pnum +\throws +What and when the call to \tcode{do_allocate} throws. +\end{itemdescr} + +\indexlibrarymember{deallocate}{memory_resource}% +\begin{itemdecl} +void deallocate(void* p, size_t bytes, size_t alignment = max_align); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{do_deallocate(p, bytes, alignment)}. +\end{itemdescr} + +\indexlibrarymember{is_equal}{memory_resource}% +\begin{itemdecl} +bool is_equal(const memory_resource& other) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return do_is_equal(other);} +\end{itemdescr} + + +\rSec3[mem.res.private]{Private virtual member functions} + +\indexlibrarymember{do_allocate}{memory_resource}% +\begin{itemdecl} +virtual void* do_allocate(size_t bytes, size_t alignment) = 0; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{alignment} is a power of two. + +\pnum +\returns +A derived class shall implement this function to +return a pointer to allocated storage\iref{basic.stc.dynamic.allocation} +with a size of at least \tcode{bytes}, +aligned to the specified \tcode{alignment}. + +\pnum +\throws +A derived class implementation shall throw an appropriate exception if it is unable to allocate memory with the requested size and alignment. +\end{itemdescr} + +\indexlibrarymember{do_deallocate}{memory_resource}% +\begin{itemdecl} +virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{p} was returned from a prior call to \tcode{allocate(bytes, alignment)} +on a memory resource equal to \tcode{*this}, +and the storage at \tcode{p} has not yet been deallocated. + +\pnum +\effects +A derived class shall implement this function to dispose of allocated storage. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibrarymember{do_is_equal}{memory_resource}% +\begin{itemdecl} +virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A derived class shall implement this function to return \tcode{true} if memory allocated from \tcode{*this} can be deallocated from \tcode{other} and vice-versa, +otherwise \tcode{false}. +\begin{note} +It is possible that the most-derived type of \tcode{other} does not match the type of \tcode{*this}. +For a derived class \tcode{D}, an implementation of this function can immediately return \tcode{false} if \tcode{dynamic_cast(\&other) == nullptr}. \end{note} @@ -5802,19 +7546,22 @@ polymorphic_allocator& operator=(const polymorphic_allocator&) = delete; // \ref{mem.poly.allocator.mem}, member functions - [[nodiscard]] Tp* allocate(size_t n); + Tp* allocate(size_t n); void deallocate(Tp* p, size_t n); - [[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); + void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t)); - template [[nodiscard]] T* allocate_object(size_t n = 1); + template T* allocate_object(size_t n = 1); template void deallocate_object(T* p, size_t n = 1); - template [[nodiscard]] T* new_object(CtorArgs&&... ctor_args); + template T* new_object(CtorArgs&&... ctor_args); template void delete_object(T* p); template void construct(T* p, Args&&... args); + template + void destroy(T* p); + polymorphic_allocator select_on_container_copy_construction() const; memory_resource* resource() const; @@ -5881,7 +7628,7 @@ \indexlibrarymember{allocate}{polymorphic_allocator}% \begin{itemdecl} -[[nodiscard]] Tp* allocate(size_t n); +Tp* allocate(size_t n); \end{itemdecl} \begin{itemdescr} @@ -5918,7 +7665,7 @@ \indexlibrarymember{allocate_bytes}{polymorphic_allocator}% \begin{itemdecl} -[[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); +void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); \end{itemdecl} \begin{itemdescr} @@ -5949,7 +7696,7 @@ \indexlibrarymember{allocate_object}{polymorphic_allocator}% \begin{itemdecl} template - [[nodiscard]] T* allocate_object(size_t n = 1); + T* allocate_object(size_t n = 1); \end{itemdecl} \begin{itemdescr} @@ -5989,7 +7736,7 @@ \indexlibrarymember{new_object}{polymorphic_allocator}% \begin{itemdecl} template - [[nodiscard]] T* new_object(CtorArgs&&... ctor_args); + T* new_object(CtorArgs&&... ctor_args); \end{itemdecl} \begin{itemdescr} @@ -6025,7 +7772,7 @@ \effects Equivalent to: \begin{codeblock} -allocator_traits::destroy(*this, p); +destroy(p); deallocate_object(p); \end{codeblock} \end{itemdescr} @@ -6055,6 +7802,18 @@ Nothing unless the constructor for \tcode{T} throws. \end{itemdescr} +\indexlibrarymember{destroy}{polymorphic_allocator}% +\begin{itemdecl} +template + void destroy(T* p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{p->\~T()}. +\end{itemdescr} + \indexlibrarymember{select_on_container_copy_construction}{polymorphic_allocator}% \begin{itemdecl} polymorphic_allocator select_on_container_copy_construction() const; @@ -6609,8 +8368,8 @@ \pnum \begin{note} The memory is released back to \tcode{upstream_rsrc} -even if some blocks that were allocated from \keyword{this} -have not been deallocated from \keyword{this}. +even if some blocks that were allocated from \tcode{*this} +have not been deallocated from \tcode{*this}. \end{note} \end{itemdescr} @@ -6790,8 +8549,8 @@ outer_allocator_type& outer_allocator() noexcept; const outer_allocator_type& outer_allocator() const noexcept; - [[nodiscard]] pointer allocate(size_type n); - [[nodiscard]] pointer allocate(size_type n, const_void_pointer hint); + pointer allocate(size_type n); + pointer allocate(size_type n, const_void_pointer hint); void deallocate(pointer p, size_type n); size_type max_size() const; @@ -7023,7 +8782,7 @@ \indexlibrarymember{allocate}{scoped_allocator_adaptor}% \begin{itemdecl} -[[nodiscard]] pointer allocate(size_type n); +pointer allocate(size_type n); \end{itemdecl} \begin{itemdescr} @@ -7034,7 +8793,7 @@ \indexlibrarymember{allocate}{scoped_allocator_adaptor}% \begin{itemdecl} -[[nodiscard]] pointer allocate(size_type n, const_void_pointer hint); +pointer allocate(size_type n, const_void_pointer hint); \end{itemdecl} \begin{itemdescr} diff --git a/source/meta.tex b/source/meta.tex index 17cbbf91dd..95d2635ed3 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -15,7 +15,7 @@ \rSec1[intseq]{Compile-time integer sequences} -\rSec2[intseq.general]{In general} +\rSec2[intseq.general]{General} \pnum The library provides a class template that can represent an integer sequence. @@ -59,9 +59,9 @@ \pnum The alias template \tcode{make_integer_sequence} denotes a specialization of -\tcode{integer_sequence} with \tcode{N} non-type template arguments. +\tcode{integer_sequence} with \tcode{N} constant template arguments. The type \tcode{make_integer_sequence} is an alias for the type -\tcode{integer_sequence}. +\tcode{integer_sequence}. \begin{note} \tcode{make_integer_sequence} is an alias for the type \tcode{integer_sequence}. @@ -138,7 +138,7 @@ \pnum Unless otherwise specified, an incomplete type may be used to instantiate a template specified in \ref{type.traits}. -The behavior of a program is undefined if: +The behavior of a program is undefined if \begin{itemize} \item an instantiation of a template specified in \ref{type.traits} @@ -160,9 +160,9 @@ template struct integral_constant; template - using bool_constant = integral_constant; - using true_type = bool_constant; - using false_type = bool_constant; + using @\libglobal{bool_constant}@ = integral_constant; + using @\libglobal{true_type}@ = bool_constant; + using @\libglobal{false_type}@ = bool_constant; // \ref{meta.unary.cat}, primary type categories template struct is_void; @@ -192,8 +192,9 @@ // \ref{meta.unary.prop}, type properties template struct is_const; template struct is_volatile; - template struct is_trivial; template struct is_trivially_copyable; + template struct is_trivially_relocatable; + template struct is_replaceable; template struct is_standard_layout; template struct is_empty; template struct is_polymorphic; @@ -244,6 +245,7 @@ template struct is_nothrow_swappable; template struct is_nothrow_destructible; + template struct is_nothrow_relocatable; template struct is_implicit_lifetime; @@ -262,6 +264,7 @@ // \ref{meta.rel}, type relations template struct is_same; template struct is_base_of; + template struct is_virtual_base_of; template struct is_convertible; template struct is_nothrow_convertible; template struct is_layout_compatible; @@ -429,10 +432,10 @@ constexpr bool @\libglobal{is_const_v}@ = is_const::value; template constexpr bool @\libglobal{is_volatile_v}@ = is_volatile::value; - template - constexpr bool @\libglobal{is_trivial_v}@ = is_trivial::value; template constexpr bool @\libglobal{is_trivially_copyable_v}@ = is_trivially_copyable::value; + template + constexpr bool @\libglobal{is_trivially_relocatable_v}@ = is_trivially_relocatable::value; template constexpr bool @\libglobal{is_standard_layout_v}@ = is_standard_layout::value; template @@ -521,8 +524,12 @@ constexpr bool @\libglobal{is_nothrow_swappable_v}@ = is_nothrow_swappable::value; template constexpr bool @\libglobal{is_nothrow_destructible_v}@ = is_nothrow_destructible::value; + template + constexpr bool @\libglobal{is_nothrow_relocatable_v}@ = is_nothrow_relocatable::value; template constexpr bool @\libglobal{is_implicit_lifetime_v}@ = is_implicit_lifetime::value; + template + constexpr bool @\libglobal{is_replaceable_v}@ = is_replaceable::value; template constexpr bool @\libglobal{has_virtual_destructor_v}@ = has_virtual_destructor::value; template @@ -548,6 +555,8 @@ constexpr bool @\libglobal{is_same_v}@ = is_same::value; template constexpr bool @\libglobal{is_base_of_v}@ = is_base_of::value; + template + constexpr bool @\libglobal{is_virtual_base_of_v}@ = is_virtual_base_of::value; template constexpr bool @\libglobal{is_convertible_v}@ = is_convertible::value; template @@ -592,7 +601,7 @@ \indexlibrarymember{value_type}{integral_constant}% \begin{codeblock} namespace std { - template struct integral_constant { + template struct @\libglobal{integral_constant}@ { static constexpr T value = v; using value_type = T; @@ -604,7 +613,6 @@ } \end{codeblock} -\indexlibraryglobal{integral_constant}% \indexlibraryglobal{bool_constant}% \indexlibraryglobal{true_type}% \indexlibraryglobal{false_type}% @@ -830,13 +838,6 @@ \tcode{T} is volatile-qualified\iref{basic.type.qualifier} & \\ \rowsep -\indexlibraryglobal{is_trivial}% -\tcode{template}\br - \tcode{struct is_trivial;} & - \tcode{T} is a trivial type\iref{term.trivial.type} & - \tcode{remove_all_extents_t} shall be a complete - type or \cv{}~\keyword{void}. \\ \rowsep - \indexlibraryglobal{is_trivially_copyable}% \tcode{template}\br \tcode{struct is_trivially_copyable;} & @@ -844,6 +845,20 @@ \tcode{remove_all_extents_t} shall be a complete type or \cv{}~\keyword{void}. \\ \rowsep +\indexlibraryglobal{is_trivially_relocatable}% +\tcode{template}\br + \tcode{struct is_trivially_relocatable;} & + \tcode{T} is a trivially relocatable type\iref{basic.types.general} & + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}. \\ \rowsep + +\indexlibraryglobal{is_replaceable}% +\tcode{template}\br + \tcode{struct is_replaceable;} & + \tcode{T} is a replaceable type\iref{basic.types.general} & + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}. \\ \rowsep + \indexlibraryglobal{is_standard_layout}% \tcode{template}\br \tcode{struct is_standard_layout;} & @@ -875,7 +890,7 @@ \indexlibraryglobal{is_final}% \tcode{template}\br \tcode{struct is_final;} & - \tcode{T} is a class type marked with the \grammarterm{class-virt-specifier} + \tcode{T} is a class type marked with the \grammarterm{class-property-specifier} \tcode{final}\iref{class.pre}. \begin{tailnote} A union is a class type that @@ -1206,6 +1221,16 @@ \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep +\indexlibraryglobal{is_nothrow_relocatable}% +\tcode{template}\br + \tcode{struct is_nothrow_relocatable;} & + \tcode{is_trivially_relocatable_v ||} + \tcode{(is_nothrow_move_constructible_v<} + \tcode{remove_all_extents_t> \&\& is_nothrow_destructible_v<} + \tcode{remove_all_extents_t>)} & + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}, \\ \rowsep + \indexlibraryglobal{is_implicit_lifetime}% \tcode{template}\br \tcode{struct is_implicit_lifetime;} & @@ -1225,8 +1250,8 @@ For an array type \tcode{T}, the same result as \tcode{has_unique_object_representations_v>}, otherwise \seebelow. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, or - an array of unknown bound. \\ \rowsep + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}. \\ \rowsep \indexlibraryglobal{reference_constructs_from_temporary}% \tcode{template}\br @@ -1341,7 +1366,7 @@ \pnum The predicate condition for a template specialization \tcode{has_unique_object_representations} -shall be satisfied if and only if: +shall be satisfied if and only if \begin{itemize} \item \tcode{T} is trivially copyable, and \item any two objects of type \tcode{T} with the same value @@ -1463,15 +1488,31 @@ 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, + not (possibly cv-qualified versions of) the same type, \tcode{Derived} shall be a complete type. \begin{tailnote} -Base classes that are private, protected, or ambiguous + Base classes that are private, protected, or ambiguous are, nonetheless, base classes. \end{tailnote} \\ \rowsep +\indexlibraryglobal{is_virtual_base_of}% +\tcode{template}\br + \tcode{struct is_virtual_base_of;} & + \tcode{Base} is a virtual base class of \tcode{Derived}\iref{class.mi} + without regard to cv-qualifiers. & + If \tcode{Base} and + \tcode{Derived} are non-union class types, + \tcode{Derived} shall be a complete type. + \begin{note} + Virtual base classes that are private, protected, or ambiguous + are, nonetheless, virtual base classes. + \end{note} + \begin{tailnote} + A class is never a virtual base class of itself. + \end{tailnote} \\ \rowsep + \indexlibraryglobal{is_convertible}% \tcode{template}\br \tcode{struct is_convertible;} & @@ -1486,7 +1527,7 @@ the conversion, as defined by \tcode{is_convertible}, is known not to throw any exceptions\iref{expr.unary.noexcept} & \tcode{From} and \tcode{To} shall be complete types, - \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep + \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep \indexlibraryglobal{is_layout_compatible}% \tcode{template}\br @@ -1888,21 +1929,18 @@ \lhdr{Template} & \rhdr{Comments} \\ \capsep \endhead -\indexlibraryglobal{type_identity}% \tcode{template\br - struct type_identity;} + struct \libglobal{type_identity};} & The member typedef \tcode{type} denotes \tcode{T}. \\ \rowsep -\indexlibraryglobal{remove_cvref}% -\tcode{template\br struct remove_cvref;} +\tcode{template\br struct \libglobal{remove_cvref};} & The member typedef \tcode{type} denotes \tcode{remove_cv_t>}. \\ \rowsep -\indexlibraryglobal{decay}% -\tcode{template\br struct decay;} +\tcode{template\br struct \libglobal{decay};} & Let \tcode{U} be \tcode{remove_reference_t}. If \tcode{is_array_v} is \tcode{true}, the member typedef \tcode{type} denotes @@ -1918,8 +1956,7 @@ \end{tailnote} \\ \rowsep -\indexlibraryglobal{enable_if}% -\tcode{template} \tcode{struct enable_if;} +\tcode{template} \tcode{struct \libglobal{enable_if};} & If \tcode{B} is \tcode{true}, the member typedef \tcode{type} denotes \tcode{T}; otherwise, there shall be no member @@ -1927,49 +1964,45 @@ \tcode{template}\br - \tcode{struct conditional;} + \tcode{struct \libglobal{conditional};} & If \tcode{B} is \tcode{true}, the member typedef \tcode{type} denotes \tcode{T}. If \tcode{B} is \tcode{false}, the member typedef \tcode{type} denotes \tcode{F}. \\ \rowsep \tcode{template} \tcode{struct common_type;} & - Unless this trait is specialized (as specified in Note B, below), - the member \tcode{type} is defined or omitted as specified in Note A, below. + Unless this trait is specialized, + the member \tcode{type} is defined or omitted as specified below. If it is omitted, there shall be no member \tcode{type}. Each type in the template parameter pack \tcode{T} shall be complete, \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep -\indexlibraryglobal{basic_common_reference}% \tcode{template class,} \hspace*{2ex}\tcode{template class>} \keyword{struct} - \hspace*{2ex}\tcode{basic_common_reference;} + \hspace*{2ex}\tcode{\libglobal{basic_common_reference};} & - Unless this trait is specialized (as specified in Note D, below), + Unless this trait is specialized, there shall be no member \tcode{type}. \\ \rowsep -\indexlibraryglobal{common_reference}% -\tcode{template} \tcode{struct common_reference;} +\tcode{template} \tcode{struct \libglobal{common_reference};} & The member \grammarterm{typedef-name} \tcode{type} is defined or omitted - as specified in Note C, below. Each type in the parameter pack \tcode{T} shall + as specified below. Each type in the parameter pack \tcode{T} shall be complete or \cv{} \keyword{void}. \\ \rowsep -\indexlibraryglobal{underlying_type}% \tcode{template}\br - \tcode{struct underlying_type;} + \tcode{struct \libglobal{underlying_type};} & If \tcode{T} is an enumeration type, the member typedef \tcode{type} denotes the underlying type of \tcode{T}\iref{dcl.enum}; otherwise, there is no member \tcode{type}.\br \mandates \tcode{T} is not an incomplete enumeration type. \\ \rowsep -\indexlibraryglobal{invoke_result}% \tcode{template}\br - \tcode{struct invoke_result;} + \tcode{struct \libglobal{invoke_result};} & If the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)}\iref{func.require} is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand}, @@ -1990,8 +2023,7 @@ are complete types, \cv{}~\keyword{void}, or arrays of unknown bound.\\ \rowsep -\indexlibraryglobal{unwrap_reference}% -\tcode{template} \tcode{struct unwrap_reference;} +\tcode{template} \tcode{struct \libglobal{unwrap_reference};} & If \tcode{T} is a specialization \tcode{reference_wrapper} for some type \tcode{X}, @@ -1999,8 +2031,7 @@ denotes \tcode{X\&}, otherwise \tcode{type} denotes \tcode{T}. \\ \rowsep -\indexlibraryglobal{unwrap_ref_decay}% -\tcode{template} \tcode{unwrap_ref_decay;} +\tcode{template} \tcode{\libglobal{unwrap_ref_decay};} & The member typedef \tcode{type} of \tcode{unwrap_ref_decay} denotes the type \tcode{unwrap_reference_t>}.\\ @@ -2066,7 +2097,6 @@ \tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed. \pnum -Note A: For the \tcode{common_type} trait applied to a template parameter pack \tcode{T} of types, the member \tcode{type} shall be either defined or not present as follows: @@ -2120,7 +2150,7 @@ \end{itemize} \pnum -Note B: Notwithstanding the provisions of \ref{meta.type.synop}, and +Notwithstanding the provisions of \ref{meta.type.synop}, and pursuant to \ref{namespace.std}, a program may specialize \tcode{common_type} for types \tcode{T1} and \tcode{T2} such that @@ -2140,7 +2170,7 @@ No diagnostic is required for a violation of this Note's rules. \pnum -Note C: For the \tcode{common_reference} trait applied to a parameter pack +For the \tcode{common_reference} trait applied to a parameter pack \tcode{T} of types, the member \tcode{type} shall be either defined or not present as follows: \begin{itemize} @@ -2186,7 +2216,7 @@ \end{itemize} \pnum -Note D: Notwithstanding the provisions of \ref{meta.type.synop}, and +Notwithstanding the provisions of \ref{meta.type.synop}, and pursuant to \ref{namespace.std}, a program may partially specialize \tcode{basic_common_reference} for types \tcode{T} and \tcode{U} such that @@ -2504,7 +2534,7 @@ } } - constexpr auto operator*() -> bool& { + constexpr auto operator*() const -> const bool& { return b; } }; @@ -2520,7 +2550,7 @@ \rSec1[ratio]{Compile-time rational arithmetic} -\rSec2[ratio.general]{In general} +\rSec2[ratio.general]{General} \pnum \indexlibraryglobal{ratio}% diff --git a/source/modules.tex b/source/modules.tex index acb04fb625..a0386b38ca 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -312,7 +312,7 @@ A redeclaration of an entity $X$ is implicitly exported if $X$ was introduced by an exported declaration; -otherwise it shall not be exported. +otherwise it shall not be exported unless it is a namespace. \begin{example} \begin{codeblock} export module M; @@ -320,6 +320,12 @@ typedef S S; export typedef S S; // OK, does not redeclare an entity export struct S; // error: exported declaration follows non-exported declaration +namespace N { // external linkage, attached to global module, not exported + void f(); +} +namespace N { // OK, exported namespace redeclaring non-exported namespace + export void g(); +} \end{codeblock} \end{example} @@ -593,7 +599,7 @@ \pnum A declaration $D$ is \defn{decl-reachable} from a declaration $S$ -in the same translation unit if: +in the same translation unit if \begin{itemize} \item $D$ does not declare a function or function template and @@ -662,6 +668,9 @@ a partial or explicit specialization or an implicit or explicit instantiation of that template, or \item +$M$ declares a class template +and $D$ is a deduction guide for that template, or +\item one of $D$ and $M$ declares a class or enumeration type and the other introduces a typedef name for linkage purposes for that type. \end{itemize} diff --git a/source/numerics.tex b/source/numerics.tex index 14308f349e..5d2ee0f222 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -17,14 +17,16 @@ as summarized in \tref{numerics.summary}. \begin{libsumtab}{Numerics library summary}{numerics.summary} -\ref{numeric.requirements} & Requirements & \\ \rowsep -\ref{cfenv} & Floating-point environment & \tcode{} \\ \rowsep -\ref{complex.numbers} & Complex numbers & \tcode{} \\ \rowsep -\ref{rand} & Random number generation & \tcode{} \\ \rowsep -\ref{numarray} & Numeric arrays & \tcode{} \\ \rowsep -\ref{c.math} & Mathematical functions for floating-point types & - \tcode{}, \tcode{} \\ \rowsep -\ref{numbers} & Numbers & \tcode{} \\ +\ref{numeric.requirements} & Requirements & \\ \rowsep +\ref{cfenv} & Floating-point environment & \tcode{} \\ \rowsep +\ref{complex.numbers} & Complex numbers & \tcode{} \\ \rowsep +\ref{rand} & Random number generation & \tcode{} \\ \rowsep +\ref{numarray} & Numeric arrays & \tcode{} \\ \rowsep +\ref{c.math} & Mathematical functions for + floating-point types & \tcode{}, \tcode{} \\ \rowsep +\ref{numbers} & Numbers & \tcode{} \\ \rowsep +\ref{linalg} & Linear algebra & \tcode{} \\ \rowsep +\ref{simd} & Data-parallel types & \tcode{} \\ \end{libsumtab} \rSec1[numeric.requirements]{Numeric type requirements} @@ -96,31 +98,20 @@ \indexlibraryglobal{feholdexcept}% \indexlibraryglobal{fesetenv}% \indexlibraryglobal{feupdateenv}% -\indexlibraryglobal{FE_ALL_EXCEPT}% -\indexlibraryglobal{FE_DIVBYZERO}% -\indexlibraryglobal{FE_INEXACT}% -\indexlibraryglobal{FE_INVALID}% -\indexlibraryglobal{FE_OVERFLOW}% -\indexlibraryglobal{FE_UNDERFLOW}% -\indexlibraryglobal{FE_DOWNWARD}% -\indexlibraryglobal{FE_TONEAREST}% -\indexlibraryglobal{FE_TOWARDZERO}% -\indexlibraryglobal{FE_UPWARD}% -\indexlibraryglobal{FE_DFL_ENV}% -\begin{codeblock} -#define FE_ALL_EXCEPT @\seebelow@ -#define FE_DIVBYZERO @\seebelow@ // optional -#define FE_INEXACT @\seebelow@ // optional -#define FE_INVALID @\seebelow@ // optional -#define FE_OVERFLOW @\seebelow@ // optional -#define FE_UNDERFLOW @\seebelow@ // optional - -#define FE_DOWNWARD @\seebelow@ // optional -#define FE_TONEAREST @\seebelow@ // optional -#define FE_TOWARDZERO @\seebelow@ // optional -#define FE_UPWARD @\seebelow@ // optional - -#define FE_DFL_ENV @\seebelow@ +\begin{codeblock} +#define @\libmacro{FE_ALL_EXCEPT}@ @\seebelow@ +#define @\libmacro{FE_DIVBYZERO}@ @\seebelow@ // optional +#define @\libmacro{FE_INEXACT}@ @\seebelow@ // optional +#define @\libmacro{FE_INVALID}@ @\seebelow@ // optional +#define @\libmacro{FE_OVERFLOW}@ @\seebelow@ // optional +#define @\libmacro{FE_UNDERFLOW}@ @\seebelow@ // optional + +#define @\libmacro{FE_DOWNWARD}@ @\seebelow@ // optional +#define @\libmacro{FE_TONEAREST}@ @\seebelow@ // optional +#define @\libmacro{FE_TOWARDZERO}@ @\seebelow@ // optional +#define @\libmacro{FE_UPWARD}@ @\seebelow@ // optional + +#define @\libmacro{FE_DFL_ENV}@ @\seebelow@ namespace std { // types @@ -211,8 +202,8 @@ Moreover, if \tcode{a} is an expression of type \cv{}~\tcode{complex*} and the expression \tcode{a[i]} is well-defined for an integer expression \tcode{i}, then: \begin{itemize} -\item \tcode{reinterpret_cast<\cv{} T*>(a)[2*i]} designates the real part of \tcode{a[i]}, and -\item \tcode{reinterpret_cast<\cv{} T*>(a)[2*i + 1]} designates the imaginary part of \tcode{a[i]}. +\item \tcode{reinterpret_cast<\cv{} T*>(a)[2 * i]} designates the real part of \tcode{a[i]}, and +\item \tcode{reinterpret_cast<\cv{} T*>(a)[2 * i + 1]} designates the imaginary part of \tcode{a[i]}. \end{itemize} \rSec2[complex.syn]{Header \tcode{} synopsis} @@ -289,16 +280,30 @@ template constexpr complex tan (const complex&); template constexpr complex tanh (const complex&); + // \ref{complex.tuple}, tuple interface + template struct tuple_size; + template struct tuple_element; + template struct tuple_size>; + template struct tuple_element>; + template + constexpr T& get(complex&) noexcept; + template + constexpr T&& get(complex&&) noexcept; + template + constexpr const T& get(const complex&) noexcept; + template + constexpr const T&& get(const complex&&) noexcept; + // \ref{complex.literals}, complex literals inline namespace literals { - inline namespace complex_literals { - constexpr complex operator""il(long double); - constexpr complex operator""il(unsigned long long); - constexpr complex operator""i(long double); - constexpr complex operator""i(unsigned long long); - constexpr complex operator""if(long double); - constexpr complex operator""if(unsigned long long); - } + inline namespace complex_literals { + constexpr complex operator""il(long double); + constexpr complex operator""il(unsigned long long); + constexpr complex operator""i(long double); + constexpr complex operator""i(unsigned long long); + constexpr complex operator""if(long double); + constexpr complex operator""if(unsigned long long); + } } } \end{codeblock} @@ -1121,6 +1126,49 @@ The complex hyperbolic tangent of \tcode{x}. \end{itemdescr} +\rSec2[complex.tuple]{Tuple interface} + +\indexlibraryglobal{tuple_size}% +\indexlibraryglobal{tuple_element}% +\begin{itemdecl} +template +struct tuple_size> : integral_constant {}; + +template +struct tuple_element> { + using type = T; +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{I < 2} is \tcode{true}. +\end{itemdescr} + +\indexlibrarymember{get}{complex}% +\begin{itemdecl} +template + constexpr T& get(complex& z) noexcept; +template + constexpr T&& get(complex&& z) noexcept; +template + constexpr const T& get(const complex& z) noexcept; +template + constexpr const T&& get(const complex&& z) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{I < 2} is \tcode{true}. + +\pnum +\returns +A reference to the real part of \tcode{z} if \tcode{I == 0} is \tcode{true}, +otherwise a reference to the imaginary part of \tcode{z}. +\end{itemdescr} + \rSec2[cmplx.over]{Additional overloads} \pnum @@ -1153,8 +1201,10 @@ Function template \tcode{pow} has additional constexpr overloads sufficient to ensure, for a call with one argument of type \tcode{complex} and the other argument of type \tcode{T2} or \tcode{complex}, -both arguments are effectively cast to \tcode{complex>}. -If \tcode{common_type_t} is not well-formed, +both arguments are effectively cast to \tcode{complex>}, +where \tcode{T3} is +\tcode{double} if \tcode{T2} is an integer type and \tcode{T2} otherwise. +If \tcode{common_type_t} is not well-formed, then the program is ill-formed. \rSec2[complex.literals]{Suffixes for complex number literals} @@ -1322,11 +1372,11 @@ namespace std { // \ref{rand.req.urng}, uniform random bit generator requirements template - concept uniform_random_bit_generator = @\seebelow@; + concept uniform_random_bit_generator = @\seebelow@; // freestanding // \ref{rand.eng.lcong}, class template \tcode{linear_congruential_engine} template - class linear_congruential_engine; + class linear_congruential_engine; // partially freestanding // \ref{rand.eng.mers}, class template \tcode{mersenne_twister_engine} template - class subtract_with_carry_engine; + class subtract_with_carry_engine; // partially freestanding // \ref{rand.adapt.disc}, class template \tcode{discard_block_engine} template - class discard_block_engine; + class discard_block_engine; // partially freestanding // \ref{rand.adapt.ibits}, class template \tcode{independent_bits_engine} template - class independent_bits_engine; + class independent_bits_engine; // partially freestanding // \ref{rand.adapt.shuf}, class template \tcode{shuffle_order_engine} template class shuffle_order_engine; + // \ref{rand.eng.philox}, class template \tcode{philox_engine} + template + class philox_engine; + // \ref{rand.predef}, engines and engine adaptors with predefined parameters - using minstd_rand0 = @\seebelow@; - using minstd_rand = @\seebelow@; - using mt19937 = @\seebelow@; - using mt19937_64 = @\seebelow@; - using ranlux24_base = @\seebelow@; - using ranlux48_base = @\seebelow@; - using ranlux24 = @\seebelow@; - using ranlux48 = @\seebelow@; + using minstd_rand0 = @\seebelow@; // freestanding + using minstd_rand = @\seebelow@; // freestanding + using mt19937 = @\seebelow@; // freestanding + using mt19937_64 = @\seebelow@; // freestanding + using ranlux24_base = @\seebelow@; // freestanding + using ranlux48_base = @\seebelow@; // freestanding + using ranlux24 = @\seebelow@; // freestanding + using ranlux48 = @\seebelow@; // freestanding using knuth_b = @\seebelow@; + using philox4x32 = @\seebelow@; + using philox4x64 = @\seebelow@; using default_random_engine = @\seebelow@; @@ -1371,12 +1427,35 @@ class seed_seq; // \ref{rand.util.canonical}, function template \tcode{generate_canonical} - template + template RealType generate_canonical(URBG& g); + namespace ranges { + // \ref{alg.rand.generate}, \tcode{generate_random} + template + requires @\libconcept{output_range}@> && + @\libconcept{uniform_random_bit_generator}@> + constexpr borrowed_iterator_t generate_random(R&& r, G&& g); + + template> O, @\libconcept{sentinel_for}@ S> + requires @\libconcept{uniform_random_bit_generator}@> + constexpr O generate_random(O first, S last, G&& g); + + template + requires @\libconcept{output_range}@> && @\libconcept{invocable}@ && + @\libconcept{uniform_random_bit_generator}@> && + is_arithmetic_v> + constexpr borrowed_iterator_t generate_random(R&& r, G&& g, D&& d); + + template> O, @\libconcept{sentinel_for}@ S> + requires @\libconcept{invocable}@ && @\libconcept{uniform_random_bit_generator}@> && + is_arithmetic_v> + constexpr O generate_random(O first, S last, G&& g, D&& d); + } + // \ref{rand.dist.uni.int}, class template \tcode{uniform_int_distribution} template - class uniform_int_distribution; + class uniform_int_distribution; // partially freestanding // \ref{rand.dist.uni.real}, class template \tcode{uniform_real_distribution} template @@ -1477,7 +1556,7 @@ \rSec3[rand.req.genl]{General requirements}% \pnum -Throughout this subclause \ref{rand}, +Throughout \ref{rand}, the effect of instantiating a template: \begin{itemize} \item @@ -1537,7 +1616,7 @@ \end{itemize} \pnum -Throughout this subclause \ref{rand}, +Throughout \ref{rand}, phrases of the form ``\tcode{x} is an iterator of a specific kind'' shall be interpreted as equivalent to the more formal requirement that ``\tcode{x} is a value @@ -1545,7 +1624,7 @@ of the specified iterator type''. \pnum -Throughout this subclause \ref{rand}, +Throughout \ref{rand}, any constructor that can be called with a single argument and that meets a requirement specified in this subclause shall be declared \keyword{explicit}. @@ -1580,8 +1659,8 @@ in \tref{rand.req.seedseq} are valid and have the indicated semantics, and if \tcode{S} also meets all other requirements -of this subclause \ref{rand.req.seedseq}. -In that Table and throughout this subclause: +of \ref{rand.req.seedseq}. +In \tref{rand.req.seedseq} and throughout this subclause: \begin{itemize} \item \tcode{T} is the type named by @@ -1626,7 +1705,7 @@ & \tcode{T} & \tcode{T} is an unsigned integer type\iref{basic.fundamental} of at least 32 bits. - & compile-time + & \\ \rowsep \tcode{S()}% & @@ -1796,8 +1875,8 @@ in \tref{rand.req.eng} are valid and have the indicated semantics, and if \tcode{E} also meets all other requirements -of this subclause \ref{rand.req.eng}. -In that Table and throughout this subclause: +of \ref{rand.req.eng}. +In \tref{rand.req.eng} and throughout this subclause: \begin{itemize} \item \tcode{T} is the type named by @@ -1835,7 +1914,8 @@ & \rhdr{Complexity} \\ \capsep \endfirsthead -\hline +\continuedcaption\\ +\topline \lhdr{Expression} & \chdr{Return type} & \chdr{Pre/post-condition} @@ -1941,51 +2021,6 @@ & \tcode{bool} & \tcode{!(x == y)}. & \bigoh{$\text{size of state}$} - \\ \rowsep -\tcode{os << x}% - & reference to the type of \tcode{os} - & With \tcode{os.}\textit{fmtflags} set to - \tcode{ios_base::dec|ios_base::left} - and the fill character set to the space character, - writes to \tcode{os} - the textual representation - of \tcode{x}'s current state. - In the output, - adjacent numbers are separated - by one or more space characters. - - \ensures The \tcode{os.}\textit{fmtflags} and fill character are unchanged. - & \bigoh{$\text{size of state}$} - \\ \rowsep -\tcode{is >> v}% - & reference to the type of \tcode{is} - & With \tcode{is.fmtflags} - set to \tcode{ios_base::dec}, - sets \tcode{v}'s state - as determined by reading its textual representation from \tcode{is}. - If bad input is encountered, - ensures that \tcode{v}'s state is unchanged by the operation - and - calls \tcode{is.setstate(ios_base::failbit)} - (which may throw \tcode{ios_base::failure}\iref{iostate.flags}). - If a textual representation written via \tcode{os << x} - was subsequently read via \tcode{is >> v}, - then \tcode{x == v} - provided that there have been no intervening invocations - of \tcode{x} or of \tcode{v}. - - \expects - \tcode{is} provides a textual representation - that was previously written - using an output stream - whose imbued locale - was the same as that of \tcode{is}, - and whose type's template specialization arguments - \tcode{charT} and \tcode{traits} - were respectively the same as those of \tcode{is}. - - \ensures The \tcode{is.}\textit{fmtflags} are unchanged. - & \bigoh{$\text{size of state}$} \\ \end{libreqtab4d} @@ -1996,6 +2031,93 @@ These operations shall each be of complexity no worse than \bigoh{\text{size of state}}. +\pnum +On hosted implementations, +the following expressions are well-formed and have the specified semantics. + +\begin{itemdecl} +os << x +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +With \tcode{os.\placeholdernc{fmtflags}} set to +\tcode{ios_base::dec|ios_base::left} +and the fill character set to the space character, +writes to \tcode{os} +the textual representation +of \tcode{x}'s current state. +In the output, +adjacent numbers are separated +by one or more space characters. + +\pnum +\ensures +The \tcode{os.\placeholdernc{fmtflags}} and fill character are unchanged. + +\pnum +\result +reference to the type of \tcode{os}. + +\pnum +\returns +\tcode{os}. + +\pnum +\complexity +\bigoh{$\text{size of state}$} +\end{itemdescr} + +\begin{itemdecl} +is >> v +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{is} provides a textual representation +that was previously written +using an output stream +whose imbued locale +was the same as that of \tcode{is}, +and whose type's template specialization arguments +\tcode{charT} and \tcode{traits} +were respectively the same as those of \tcode{is}. + +\pnum +\effects +With \tcode{is.\placeholdernc{fmtflags}} +set to \tcode{ios_base::dec}, +sets \tcode{v}'s state +as determined by reading its textual representation from \tcode{is}. +If bad input is encountered, +ensures that \tcode{v}'s state is unchanged by the operation +and +calls \tcode{is.setstate(ios_base::failbit)} +(which may throw \tcode{ios_base::failure}\iref{iostate.flags}). +If a textual representation written via \tcode{os << x} +was subsequently read via \tcode{is >> v}, +then \tcode{x == v} +provided that there have been no intervening invocations +of \tcode{x} or of \tcode{v}. + +\pnum +\ensures +The \tcode{is.\placeholdernc{fmtflags}} are unchanged. + +\pnum +\result +reference to the type of \tcode{is}. + +\pnum +\returns +\tcode{is}. + +\pnum +\complexity +\bigoh{$\text{size of state}$} +\end{itemdescr} \indextext{requirements!random number engine|)} \indextext{random number engine!requirements|)}% @@ -2175,8 +2297,8 @@ are valid and have the indicated semantics, and if \tcode{D} and its associated types also meet all other requirements -of this subclause \ref{rand.req.dist}. -In that Table and throughout this subclause, +of \ref{rand.req.dist}. +In \tref{rand.req.dist} and throughout this subclause, \begin{itemize} \item \tcode{T} is the type named by @@ -2223,7 +2345,8 @@ & \rhdr{Complexity} \\ \capsep \endfirsthead -\hline +\continuedcaption\\ +\topline \lhdr{Expression} & \chdr{Return type} & \chdr{Pre/post-condition} @@ -2233,12 +2356,12 @@ \tcode{D::result_type} & \tcode{T} & \tcode{T} is an arithmetic type\iref{basic.fundamental}. - & compile-time + & \\ \rowsep \tcode{D::param_type} & \tcode{P} & - & compile-time + & \\ \rowsep \tcode{D()}% & @@ -2327,35 +2450,6 @@ & \tcode{bool} & \tcode{!(x == y)}. & same as \tcode{x == y}. - \\ \rowsep -\tcode{os << x} - & reference to the type of \tcode{os} - & Writes to \tcode{os} a textual representation - for the parameters and the additional internal data of \tcode{x}. - - \ensures The \tcode{os.}\textit{fmtflags} and fill character are unchanged. - & - \\ \rowsep -\tcode{is >> d} - & reference to the type of \tcode{is} - & Restores from \tcode{is} - the parameters and additional internal data of the lvalue \tcode{d}. - If bad input is encountered, - ensures that \tcode{d} is unchanged by the operation - and - calls \tcode{is.setstate(ios_base::failbit)} - (which may throw \tcode{ios_base::failure}\iref{iostate.flags}). - - \expects - \tcode{is} provides a textual representation - that was previously written - using an \tcode{os} whose imbued locale - and whose type's template specialization arguments - \tcode{charT} and \tcode{traits} - were the same as those of \tcode{is}. - - \ensures The \tcode{is.}\textit{fmtflags} are unchanged. - & \\ \end{libreqtab4d} @@ -2386,7 +2480,7 @@ It is unspecified whether \tcode{D::param_type} is declared as a (nested) \keyword{class} or via a \keyword{typedef}. -In this subclause \ref{rand}, +In \ref{rand}, declarations of \tcode{D::param_type} are in the form of \keyword{typedef}s for convenience of exposition only. @@ -2416,6 +2510,70 @@ using distribution_type = D; \end{codeblock} +\pnum +On hosted implementations, +the following expressions are well-formed and have the specified semantics. + +\begin{itemdecl} +os << x +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Writes to \tcode{os} a textual representation +for the parameters and the additional internal data of \tcode{x}. + +\pnum +\ensures +The \tcode{os.\placeholdernc{fmtflags}} and fill character are unchanged. + +\pnum +\result +reference to the type of \tcode{os}. + +\pnum +\returns +\tcode{os}. +\end{itemdescr} + +\begin{itemdecl} +is >> d +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{is} provides a textual representation +that was previously written +using an \tcode{os} whose imbued locale +and whose type's template specialization arguments +\tcode{charT} and \tcode{traits} +were the same as those of \tcode{is}. + +\pnum +\effects +Restores from \tcode{is} +the parameters and additional internal data of the lvalue \tcode{d}. +If bad input is encountered, +ensures that \tcode{d} is unchanged by the operation +and +calls \tcode{is.setstate(ios_base::failbit)} +(which may throw \tcode{ios_base::failure}\iref{iostate.flags}). + +\pnum +\ensures +The \tcode{is.\placeholdernc{fmtflags}} are unchanged. + +\pnum +\result +reference to the type of \tcode{is}. + +\pnum +\returns +\tcode{is}. +\end{itemdescr} + \indextext{requirements!random number distribution|)}% \indextext{random number distribution!requirements|)}% \indextext{random number generation!requirements|)} @@ -2474,7 +2632,7 @@ \pnum Each template specified in \ref{rand.eng} requires one or more relationships, -involving the value(s) of its non-type template parameter(s), to hold. +involving the value(s) of its constant template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold. @@ -2559,10 +2717,12 @@ // inserters and extractors template friend basic_ostream& - operator<<(basic_ostream& os, const linear_congruential_engine& x); + operator<<(basic_ostream& os, // hosted + const linear_congruential_engine& x); template friend basic_istream& - operator>>(basic_istream& is, linear_congruential_engine& x); + operator>>(basic_istream& is, // hosted + linear_congruential_engine& x); }; } \end{codeblock} @@ -2571,7 +2731,7 @@ If the template parameter \tcode{m} is $0$, the modulus $m$ -used throughout this subclause~\ref{rand.eng.lcong} +used throughout \ref{rand.eng.lcong} is \tcode{numeric_limits::max()} plus $1$. \begin{note} $m$ need not be representable @@ -2739,10 +2899,12 @@ // inserters and extractors template friend basic_ostream& - operator<<(basic_ostream& os, const mersenne_twister_engine& x); + operator<<(basic_ostream& os, // hosted + const mersenne_twister_engine& x); template friend basic_istream& - operator>>(basic_istream& is, mersenne_twister_engine& x); + operator>>(basic_istream& is, // hosted + mersenne_twister_engine& x); }; } \end{codeblock} @@ -2758,12 +2920,12 @@ \tcode{t <= w}, \tcode{l <= w}, \tcode{w <= numeric_limits::digits}, - \tcode{a <= (1u< explicit subtract_with_carry_engine(Sseq& q); - void seed(result_type value = default_seed); + void seed(result_type value = 0u); template void seed(Sseq& q); // equality operators @@ -2905,10 +3067,12 @@ // inserters and extractors template friend basic_ostream& - operator<<(basic_ostream& os, const subtract_with_carry_engine& x); + operator<<(basic_ostream& os, // hosted + const subtract_with_carry_engine& x); template friend basic_istream& - operator>>(basic_istream& is, subtract_with_carry_engine& x); + operator>>(basic_istream& is, // hosted + subtract_with_carry_engine& x); }; } \end{codeblock} @@ -2946,8 +3110,8 @@ first construct \tcode{e}, a \tcode{linear_congruential_engine} object, as if by the following definition: \begin{codeblock} -linear_congruential_engine e(value == 0u ? default_seed : value); +linear_congruential_engine e( + value == 0u ? default_seed : static_cast(value % 2147483563u)); \end{codeblock} Then, to set each $X_k$, obtain new values $z_0, \dotsc, z_{n-1}$ @@ -2982,6 +3146,237 @@ otherwise sets $c$ to $0$. \end{itemdescr} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% philox_engine engine: + +\rSec3[rand.eng.philox]{Class template \tcode{philox_engine}}% +\indexlibraryglobal{philox_engine}% + +\pnum +A \tcode{philox_engine} random number engine produces +unsigned integer random numbers in the interval \range{0}{$m$}, +where $m = 2^w$ and +the template parameter $w$ defines the range of the produced numbers. +The state of a \tcode{philox_engine} object consists of +a sequence $X$ of $n$ unsigned integer values of width $w$, +a sequence $K$ of $n/2$ values of \tcode{result_type}, +a sequence $Y$ of $n$ values of \tcode{result_type}, and +a scalar $i$, where +\begin{itemize} +\item +$X$ is the interpretation of the unsigned integer \term{counter} value +$Z \cedef \sum_{j = 0}^{n - 1} X_j \cdot 2^{wj}$ of $n \cdot w$ bits, +\item +$K$ are keys, which are generated once from the seed (see constructors below) +and remain constant unless the \tcode{seed} function\iref{rand.req.eng} is invoked, +\item +$Y$ stores a batch of output values, and +\item +$i$ is an index for an element of the sequence $Y$. +\end{itemize} + +\pnum +The generation algorithm returns $Y_i$, +the value stored in the $i^{th}$ element of $Y$ after applying +the transition algorithm. + +\pnum +The state transition is performed as if by the following algorithm: +\begin{codeblock} +@$i$@ = @$i$@ + 1 +if (@$i$@ == @$n$@) { + @$Y$@ = Philox(@$K$@, @$X$@) // \seebelow + @$Z$@ = @$Z$@ + 1 + @$i$@ = 0 +} +\end{codeblock} + +\pnum +The \tcode{Philox} function maps the length-$n/2$ sequence $K$ and +the length-$n$ sequence $X$ into a length-$n$ output sequence $Y$. +Philox applies an $r$-round substitution-permutation network to the values in $X$. +A single round of the generation algorithm performs the following steps: +\begin{itemize} +\item +The output sequence $X'$ of the previous round +($X$ in case of the first round) +is permuted to obtain the intermediate state $V$: +\begin{codeblock} +@$V_j = X'_{f_n(j)}$@ +\end{codeblock} +where $j = 0, \dotsc, n - 1$ and +$f_n(j)$ is defined in \tref{rand.eng.philox.f}. + +\begin{floattable}{Values for the word permutation $\bm{f}_{\bm{n}}\bm{(j)}$}{rand.eng.philox.f} +{l|l|l|l|l|l} +\topline + \multicolumn{2}{|c|}{$\bm{f}_{\bm{n}}\bm{(j)}$} & \multicolumn{4}{c|}{$\bm{j}$} \\ \cline{3-6} + \multicolumn{2}{|c|}{} + & 0 & 1 & 2 & 3 \\ \hline + $\bm{n} $ & 2 & 0 & 1 & \multicolumn{2}{c|}{} \\ \cline{2-6} + & 4 & 2 & 1 & 0 & 3 \\ \cline{2-6} +\end{floattable} +\begin{note} +For $n = 2$ the sequence is not permuted. +\end{note} + +\item +The following computations are applied to the elements of the $V$ sequence: +\begin{codeblock} +@$X_{2k + 0} = \mulhi(V_{2k}, M_{k}, w) \xor \mathit{key}^q_k \xor V_{2k + 1}$@ +@$X_{2k + 1} = \mullo(V_{2k}, M_{k}, w)$@ +\end{codeblock} +where: + \begin{itemize} + \item + $\mullo(\tcode{a}, \tcode{b}, \tcode{w})$ is + the low half of the modular multiplication of \tcode{a} and \tcode{b}: + $(\tcode{a} \cdot \tcode{b}) \mod 2^w$, + + \item + $\mulhi(\tcode{a}, \tcode{b}, \tcode{w})$ is + the high half of the modular multiplication of \tcode{a} and \tcode{b}: + $(\left\lfloor (\tcode{a} \cdot \tcode{b}) / 2^w \right\rfloor)$, + + \item + $k = 0, \dotsc, n/2 - 1$ is the index in the sequences, + + \item + $q = 0, \dotsc, r - 1$ is the index of the round, + + \item + $\mathit{key}^q_k$ is the $k^\text{th}$ round key for round $q$, + $\mathit{key}^q_k \cedef (K_k + q \cdot C_k) \mod 2^w$, + + \item + $K_k$ are the elements of the key sequence $K$, + + \item + $M_k$ is \tcode{multipliers[$k$]}, and + + \item + $C_k$ is \tcode{round_consts[$k$]}. + \end{itemize} +\end{itemize} + +\pnum +After $r$ applications of the single-round function, +\tcode{Philox} returns the sequence $Y = X'$. + +\indexlibraryglobal{philox_engine}% +\indexlibrarymember{result_type}{philox_engine}% +\begin{codeblock} +namespace std { + template + class philox_engine { + static constexpr size_t @\exposid{array-size}@ = n / 2; // \expos + public: + // types + using result_type = UIntType; + + // engine characteristics + static constexpr size_t word_size = w; + static constexpr size_t word_count = n; + static constexpr size_t round_count = r; + static constexpr array multipliers; + static constexpr array}@ round_consts; + static constexpr result_type min() { return 0; } + static constexpr result_type max() { return m - 1; } + static constexpr result_type default_seed = 20111115u; + + // constructors and seeding functions + philox_engine() : philox_engine(default_seed) {} + explicit philox_engine(result_type value); + template explicit philox_engine(Sseq& q); + void seed(result_type value = default_seed); + template void seed(Sseq& q); + + void set_counter(const array& counter); + + // equality operators + friend bool operator==(const philox_engine& x, const philox_engine& y); + + // generating functions + result_type operator()(); + void discard(unsigned long long z); + + // inserters and extractors + template + friend basic_ostream& + operator<<(basic_ostream& os, const philox_engine& x); + template + friend basic_istream& + operator>>(basic_istream& is, philox_engine& x); + }; +} +\end{codeblock} + +\pnum +\mandates +\begin{itemize} +\item \tcode{sizeof...(consts) == n} is \tcode{true}, and +\item \tcode{n == 2 || n == 4} is \tcode{true}, and +\item \tcode{0 < r} is \tcode{true}, and +\item \tcode{0 < w \&\& w <= numeric_limits::digits} is \tcode{true}. +\end{itemize} + +\pnum +The template parameter pack \tcode{consts} represents +the $M_k$ and $C_k$ constants which are grouped as follows: +$[ M_0, C_0, M_1, C_1, M_2, C_2, \dotsc, M_{n/2 - 1}, C_{n/2 - 1} ]$. + +\pnum +The textual representation consists of the values of +$K_0, \dotsc, K_{n/2 - 1}, X_{0}, \dotsc, X_{n - 1}, i$, in that order. +\begin{note} +The stream extraction operator can reconstruct $Y$ from $K$ and $X$, as needed. +\end{note} + +\indexlibraryctor{philox_engine} +\begin{itemdecl} +explicit philox_engine(result_type value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Sets the $K_0$ element of sequence $K$ to $\tcode{value} \mod 2^w$. +All elements of sequences $X$ and $K$ (except $K_0$) are set to \tcode{0}. +The value of $i$ is set to $n - 1$. +\end{itemdescr} + +\indexlibraryctor{philox_engine} +\begin{itemdecl} +template explicit philox_engine(Sseq& q); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +With $p = \left\lceil w / 32 \right\rceil$ and +an array (or equivalent) \tcode{a} of length $(n/2) \cdot p$, +invokes \tcode{q.generate(a + 0, a + n / 2 * $p$)} and +then iteratively for $k = 0, \dotsc, n/2 - 1$, +sets $K_k$ to +$\left(\sum_{j = 0}^{p - 1} a_{k p + j} \cdot 2^{32j} \right) \mod 2^w$. +All elements of sequence $X$ are set to \tcode{0}. +The value of $i$ is set to $n - 1$. +\end{itemdescr} + +\indexlibrarymember{set_counter}{philox_engine}% +\begin{itemdecl} +void set_counter(const array& c); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +For $j = 0, \dotsc, n - 1$ sets $X_j$ to $C_{n - 1 - j} \mod 2^w$. +The value of $i$ is set to $n - 1$. +\begin{note} +The counter is the value $Z$ introduced at the beginning of this subclause. +\end{note} +\end{itemdescr} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2994,34 +3389,34 @@ \rSec2[rand.adapt]{Random number engine adaptor class templates} -\rSec3[rand.adapt.general]{In general} +\rSec3[rand.adapt.general]{General} \pnum Each type instantiated -from a class template specified in this subclause~\ref{rand.adapt} +from a class template specified in \ref{rand.adapt} meets the requirements of a random number engine adaptor\iref{rand.req.adapt} type. \pnum Except where specified otherwise, the complexity of each function -specified in this subclause~\ref{rand.adapt} +specified in \ref{rand.adapt} is constant. \pnum Except where specified otherwise, -no function described in this subclause~\ref{rand.adapt} +no function described in \ref{rand.adapt} throws an exception. \pnum -Every function described in this subclause~\ref{rand.adapt} +Every function described in \ref{rand.adapt} that has a function parameter \tcode{q} of type \tcode{Sseq\&} for a template type parameter named \tcode{Sseq} that is different from type \tcode{seed_seq} throws what and when the invocation of \tcode{q.generate} throws. \pnum -Descriptions are provided in this subclause~\ref{rand.adapt} +Descriptions are provided in \ref{rand.adapt} only for adaptor operations that are not described in subclause~\ref{rand.req.adapt} or for operations where there is additional semantic information. @@ -3033,9 +3428,9 @@ are not shown in the synopses. \pnum -Each template specified in this subclause~\ref{rand.adapt} +Each template specified in \ref{rand.adapt} requires one or more relationships, -involving the value(s) of its non-type template parameter(s), to hold. +involving the value(s) of its constant template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold. @@ -3114,10 +3509,10 @@ // inserters and extractors template friend basic_ostream& - operator<<(basic_ostream& os, const discard_block_engine& x); + operator<<(basic_ostream& os, const discard_block_engine& x); // hosted template friend basic_istream& - operator>>(basic_istream& is, discard_block_engine& x); + operator>>(basic_istream& is, discard_block_engine& x); // hosted private: Engine e; // \expos @@ -3229,7 +3624,8 @@ \indexlibraryglobal{independent_bits_engine}% \indexlibrarymember{result_type}{independent_bits_engine}% \begin{codeblock} -template +namespace std { + template class independent_bits_engine { public: // types @@ -3262,14 +3658,15 @@ // inserters and extractors template friend basic_ostream& - operator<<(basic_ostream& os, const independent_bits_engine& x); + operator<<(basic_ostream& os, const independent_bits_engine& x); // hosted template friend basic_istream& - operator>>(basic_istream& is, independent_bits_engine& x); + operator>>(basic_istream& is, independent_bits_engine& x); // hosted private: Engine e; // \expos }; +} \end{codeblock}% \pnum @@ -3396,7 +3793,7 @@ each constructor% \indexlibraryctor{shuffle_order_engine} that is not a copy constructor -initializes $\tcode{V[0]}, \dotsc, \tcode{V[k-1]}$ and $Y$, +initializes $\tcode{V[0]}, \dotsc, \tcode{V[k - 1]}$ and $Y$, in that order, with values returned by successive invocations of \tcode{e()}.% \indextext{random number generation!engines|)} @@ -3581,10 +3978,40 @@ need not generate identical sequences across implementations. \end{note} \end{itemdescr}% -\indextext{random number generation!predefined engines and adaptors|)}% -\indextext{random number engine adaptor!with predefined parameters|)}% -\indextext{random number engine!with predefined parameters|)} - + +\indexlibraryglobal{philox4x32}% +\begin{itemdecl} +using philox4x32 = + philox_engine; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\required +The $10000^\text{th}$ consecutive invocation +a default-constructed object of type \tcode{philox4x32} +produces the value $1955073260$. +\end{itemdescr}% + +\indexlibraryglobal{philox4x64}% +\begin{itemdecl} +using philox4x64 = + philox_engine; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\required +The $10000^\text{th}$ consecutive invocation +a default-constructed object of type \tcode{philox4x64} +produces the value $3409172418970261260$. +\end{itemdescr}% +\indextext{random number generation!predefined engines and adaptors|)}% +\indextext{random number engine adaptor!with predefined parameters|)}% +\indextext{random number engine!with predefined parameters|)} + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -3971,28 +4398,46 @@ \indexlibraryglobal{generate_canonical}% \begin{itemdecl} -template +template RealType generate_canonical(URBG& g); \end{itemdecl} \begin{itemdescr} +\pnum +Let +\begin{itemize} +\item $r$ be \tcode{numeric_limits::radix}, +\item $R$ be $\tcode{g.max()} - \tcode{g.min()} + 1$, +\item $d$ be the smaller of + \tcode{digits} and \tcode{numeric_limits::digits}, + \begin{footnote} + $d$ is introduced to avoid any attempt + to produce more bits of randomness + than can be held in \tcode{RealType}. + \end{footnote} +\item $k$ be the smallest integer such that $R^k \ge r^d$, and +\item $x$ be $\left\lfloor R^k / r^d \right\rfloor$. +\end{itemize} +An \defn{attempt} is $k$ invocations of \tcode{g()} +to obtain values $g_0, \dotsc, g_{k-1}$, respectively, +and the calculation of a quantity $S$ given by \eqref{rand.gencanonical}: +\begin{formula}{rand.gencanonical} +S = \sum_{i=0}^{k-1} (g_i - \tcode{g.min()}) \cdot R^i +\end{formula} + \pnum \effects - Invokes \tcode{g()} $k$ times - to obtain values $g_0, \dotsc, g_{k-1}$, respectively. - Calculates a quantity - \[ - S = \sum_{i=0}^{k-1} (g_i - \tcode{g.min()}) - \cdot R^i - \] - using arithmetic of type - \tcode{RealType}. +Attempts are made until $S < xr^d$. +\begin{note} +When $R$ is a power of $r$, precisely one attempt is made. +\end{note} \pnum \returns -$S / R^k$. +$\left\lfloor S / x \right\rfloor / r^d$. \begin{note} -$0 \leq S / R^k < 1$. +The return value $c$ satisfies +$0 \leq c < 1$. \end{note} \pnum @@ -4001,21 +4446,7 @@ \pnum \complexity -Exactly - $k = \max(1, \left\lceil b / \log_2 R \right\rceil)$ - invocations - of \tcode{g}, - where $b$ -\begin{footnote} -$b$ is introduced - to avoid any attempt - to produce more bits of randomness - than can be held in \tcode{RealType}. -\end{footnote} - is the lesser of \tcode{numeric_limits::digits} - and \tcode{bits}, - and - $R$ is the value of $\tcode{g.max()} - \tcode{g.min()} + 1$. +Exactly $k$ invocations of \tcode{g} per attempt. \pnum \begin{note} @@ -4028,6 +4459,13 @@ into a value that can be delivered by a random number distribution. \end{note} + +\pnum +\begin{note} +When $R$ is a power of $r$, +an implementation can avoid using an arithmetic type that is wider +than the output when computing $S$. +\end{note} \end{itemdescr} \indextext{random number generation!utilities|)} @@ -4045,16 +4483,16 @@ \rSec2[rand.dist]{Random number distribution class templates}% \indextext{random number generation!distributions|(} -\rSec3[rand.dist.general]{In general} +\rSec3[rand.dist.general]{General} \pnum Each type instantiated -from a class template specified in this subclause~\ref{rand.dist} +from a class template specified in \ref{rand.dist} meets the requirements of a random number distribution\iref{rand.req.dist} type. \pnum -Descriptions are provided in this subclause~\ref{rand.dist} +Descriptions are provided in \ref{rand.dist} only for distribution operations that are not described in \ref{rand.req.dist} or for operations where there is additional semantic information. @@ -4098,8 +4536,11 @@ produces random integers $i$, $a \leq i \leq b$, distributed according to -the constant discrete probability function% -\[ P(i\,|\,a,b) = 1 / (b - a + 1) \text{ .} \] +the constant discrete probability function in \eqref{rand.dist.uni.int}. + +\begin{formula}{rand.dist.uni.int} +P(i\,|\,a,b) = 1 / (b - a + 1) +\end{formula} \indexlibraryglobal{uniform_int_distribution}% \indexlibrarymember{result_type}{uniform_int_distribution}% @@ -4138,10 +4579,12 @@ // inserters and extractors template friend basic_ostream& - operator<<(basic_ostream& os, const uniform_int_distribution& x); + operator<<(basic_ostream& os, // hosted + const uniform_int_distribution& x); template friend basic_istream& - operator>>(basic_istream& is, uniform_int_distribution& x); + operator>>(basic_istream& is, // hosted + uniform_int_distribution& x); }; } \end{codeblock} @@ -4198,8 +4641,10 @@ produces random numbers $x$, $a \leq x < b$, distributed according to -the constant probability density function% -\[ p(x\,|\,a,b) = 1 / (b - a) \text{ .} \] +the constant probability density function in \eqref{rand.dist.uni.real}. +\begin{formula}{rand.dist.uni.real} +p(x\,|\,a,b) = 1 / (b - a) +\end{formula} \begin{note} This implies that $p(x\,|\,a,b)$ is undefined when \tcode{a == b}. \end{note} @@ -4316,12 +4761,13 @@ A \tcode{bernoulli_distribution} random number distribution produces \tcode{bool} values $b$ distributed according to -the discrete probability function -\[ P(b\,|\,p) = \left\{ \begin{array}{ll} - p & \text{ if $b = \tcode{true}$, or} \\ - 1 - p & \text{ if $b = \tcode{false}$.} +the discrete probability function in \eqref{rand.dist.bern.bernoulli}. +\begin{formula}{rand.dist.bern.bernoulli} +P(b\,|\,p) = \left\{ \begin{array}{ll} + p & \text{ if $b = \tcode{true}$} \\ + 1 - p & \text{ if $b = \tcode{false}$} \end{array}\right. -\] +\end{formula} \indexlibraryglobal{bernoulli_distribution}% \indexlibrarymember{result_type}{bernoulli_distribution}% @@ -4405,8 +4851,11 @@ A \tcode{binomial_distribution} random number distribution produces integer values $i \geq 0$ distributed according to -the discrete probability function% -\[ P(i\,|\,t,p) = \binom{t}{i} \cdot p^i \cdot (1-p)^{t-i} \text{ .} \] +the discrete probability function in \eqref{rand.dist.bern.bin}. + +\begin{formula}{rand.dist.bern.bin} +P(i\,|\,t,p) = \binom{t}{i} \cdot p^i \cdot (1-p)^{t-i} +\end{formula} \indexlibraryglobal{binomial_distribution}% \indexlibrarymember{result_type}{binomial_distribution}% @@ -4503,8 +4952,10 @@ A \tcode{geometric_distribution} random number distribution produces integer values $i \geq 0$ distributed according to -the discrete probability function -\[ P(i\,|\,p) = p \cdot (1-p)^{i} \text{ .} \] +the discrete probability function in \eqref{rand.dist.bern.geo}. +\begin{formula}{rand.dist.bern.geo} +P(i\,|\,p) = p \cdot (1-p)^{i} +\end{formula} \indexlibraryglobal{geometric_distribution}% \indexlibrarymember{result_type}{geometric_distribution}% @@ -4590,8 +5041,10 @@ A \tcode{negative_binomial_distribution} random number distribution produces random integers $i \geq 0$ distributed according to -the discrete probability function -\[ P(i\,|\,k,p) = \binom{k+i-1}{i} \cdot p^k \cdot (1-p)^i \text{ .} \] +the discrete probability function in \eqref{rand.dist.bern.negbin}. +\begin{formula}{rand.dist.bern.negbin} +P(i\,|\,k,p) = \binom{k+i-1}{i} \cdot p^k \cdot (1-p)^i +\end{formula} \begin{note} This implies that $P(i\,|\,k,p)$ is undefined when \tcode{p == 1}. \end{note} @@ -4707,18 +5160,19 @@ A \tcode{poisson_distribution} random number distribution produces integer values $i \geq 0$ distributed according to -the discrete probability function -\[ P(i\,|\,\mu) = \frac{e^{-\mu} \mu^{i}}{i\,!} \text{ .} \] +the discrete probability function in \eqref{rand.dist.pois.poisson}. +\begin{formula}{rand.dist.pois.poisson} +P(i\,|\,\mu) = \frac{e^{-\mu} \mu^{i}}{i\,!} +\end{formula} The distribution parameter $\mu$ -is also known as this distribution's \term{mean}% -. +is also known as this distribution's \term{mean}. \indexlibraryglobal{poisson_distribution}% \indexlibrarymember{result_type}{poisson_distribution}% \begin{codeblock} -template - class poisson_distribution - { +namespace std { + template + class poisson_distribution { public: // types using result_type = IntType; @@ -4754,6 +5208,7 @@ friend basic_istream& operator>>(basic_istream& is, poisson_distribution& x); }; +} \end{codeblock} \indexlibraryctor{poisson_distribution}% @@ -4793,8 +5248,10 @@ An \tcode{exponential_distribution} random number distribution produces random numbers $x > 0$ distributed according to -the probability density function% -\[ p(x\,|\,\lambda) = \lambda e^{-\lambda x} \text{ .} \] +the probability density function in \eqref{rand.dist.pois.exp}. +\begin{formula}{rand.dist.pois.exp} +p(x\,|\,\lambda) = \lambda e^{-\lambda x} +\end{formula} \indexlibraryglobal{exponential_distribution}% \indexlibrarymember{result_type}{exponential_distribution}% @@ -4878,10 +5335,11 @@ A \tcode{gamma_distribution} random number distribution produces random numbers $x > 0$ distributed according to -the probability density function% -\[ p(x\,|\,\alpha,\beta) = +the probability density function in \eqref{rand.dist.pois.gamma}. +\begin{formula}{rand.dist.pois.gamma} +p(x\,|\,\alpha,\beta) = \frac{e^{-x/\beta}}{\beta^{\alpha} \cdot \Gamma(\alpha)} \, \cdot \, x^{\, \alpha-1} - \text{ .} \] +\end{formula} \indexlibraryglobal{gamma_distribution}% \indexlibrarymember{result_type}{gamma_distribution}% @@ -4980,11 +5438,12 @@ A \tcode{weibull_distribution} random number distribution produces random numbers $x \geq 0$ distributed according to -the probability density function% -\[ p(x\,|\,a,b) = \frac{a}{b} +the probability density function in \eqref{rand.dist.pois.weibull}. +\begin{formula}{rand.dist.pois.weibull} +p(x\,|\,a,b) = \frac{a}{b} \cdot \left(\frac{x}{b}\right)^{a-1} \cdot \, \exp\left( -\left(\frac{x}{b}\right)^a\right) - \text{ .} \] +\end{formula} \indexlibraryglobal{weibull_distribution}% \indexlibrarymember{result_type}{weibull_distribution}% @@ -5082,7 +5541,7 @@ An \tcode{extreme_value_distribution} random number distribution produces random numbers $x$ distributed according to -the probability density function +the probability density function in \eqref{rand.dist.pois.extreme}. \begin{footnote} The distribution corresponding to this probability density function @@ -5093,9 +5552,10 @@ or the Fisher-Tippett Type I distribution. \end{footnote} -\[ p(x\,|\,a,b) = \frac{1}{b} +\begin{formula}{rand.dist.pois.extreme} +p(x\,|\,a,b) = \frac{1}{b} \cdot \exp\left(\frac{a-x}{b} - \exp\left(\frac{a-x}{b}\right)\right) - \text{ .} \] +\end{formula} \indexlibraryglobal{extreme_value_distribution}% \indexlibrarymember{result_type}{extreme_value_distribution}% @@ -5207,8 +5667,8 @@ A \tcode{normal_distribution} random number distribution produces random numbers $x$ distributed according to -the probability density function% -\[% +the probability density function in \eqref{rand.dist.norm.normal}. +\begin{formula}{rand.dist.norm.normal} p(x\,|\,\mu,\sigma) = \frac{1}{\sigma \sqrt{2\pi}} \cdot @@ -5217,8 +5677,7 @@ {2 \sigma^2} \right) } - \text{ .} -\] +\end{formula} The distribution parameters $\mu$ and $\sigma$ are also known as this distribution's \term{mean} and \term{standard deviation}. @@ -5320,10 +5779,11 @@ A \tcode{lognormal_distribution} random number distribution produces random numbers $x > 0$ distributed according to -the probability density function% -\[ p(x\,|\,m,s) = \frac{1}{s x \sqrt{2 \pi}} +the probability density function in \eqref{rand.dist.norm.lognormal}. +\begin{formula}{rand.dist.norm.lognormal} +p(x\,|\,m,s) = \frac{1}{s x \sqrt{2 \pi}} \cdot \exp{\left(-\frac{(\ln{x} - m)^2}{2 s^2}\right)} - \text{ .} \] +\end{formula} \indexlibraryglobal{lognormal_distribution}% \indexlibrarymember{result_type}{lognormal_distribution}% @@ -5422,8 +5882,10 @@ A \tcode{chi_squared_distribution} random number distribution produces random numbers $x > 0$ distributed according to -the probability density function% -\[ p(x\,|\,n) = \frac{x^{(n/2)-1} \cdot e^{-x/2}}{\Gamma(n/2) \cdot 2^{n/2}} \text{ .} \] +the probability density function in \eqref{rand.dist.norm.chisq}. +\begin{formula}{rand.dist.norm.chisq} +p(x\,|\,n) = \frac{x^{(n/2)-1} \cdot e^{-x/2}}{\Gamma(n/2) \cdot 2^{n/2}} +\end{formula} \indexlibraryglobal{chi_squared_distribution}% \indexlibrarymember{result_type}{chi_squared_distribution}% @@ -5508,8 +5970,10 @@ A \tcode{cauchy_distribution} random number distribution produces random numbers $x$ distributed according to -the probability density function% -\[ p(x\,|\,a,b) = \left(\pi b \left(1 + \left(\frac{x-a}{b} \right)^2 \, \right)\right)^{-1} \text{ .} \] +the probability density function in \eqref{rand.dist.norm.cauchy}. +\begin{formula}{rand.dist.norm.cauchy} +p(x\,|\,a,b) = \left(\pi b \left(1 + \left(\frac{x-a}{b} \right)^2 \, \right)\right)^{-1} +\end{formula} \indexlibraryglobal{cauchy_distribution}% \indexlibrarymember{result_type}{cauchy_distribution}% @@ -5608,12 +6072,13 @@ A \tcode{fisher_f_distribution} random number distribution produces random numbers $x \ge 0$ distributed according to -the probability density function% -\[ p(x\,|\,m,n) = \frac{\Gamma\big((m+n)/2\big)}{\Gamma(m/2) \; \Gamma(n/2)} +the probability density function in \eqref{rand.dist.norm.f}. +\begin{formula}{rand.dist.norm.f} +p(x\,|\,m,n) = \frac{\Gamma\big((m+n)/2\big)}{\Gamma(m/2) \; \Gamma(n/2)} \cdot \left(\frac{m}{n}\right)^{m/2} \cdot x^{(m/2)-1} \cdot \left(1 + \frac{m x}{n}\right)^{-(m + n)/2} - \text{ .} \] +\end{formula} \indexlibraryglobal{fisher_f_distribution}% \indexlibrarymember{result_type}{fisher_distribution}% @@ -5712,11 +6177,12 @@ A \tcode{student_t_distribution} random number distribution produces random numbers $x$ distributed according to -the probability density function% -\[ p(x\,|\,n) = \frac{1}{\sqrt{n \pi}} +the probability density function in \eqref{rand.dist.norm.t}. +\begin{formula}{rand.dist.norm.t} +p(x\,|\,n) = \frac{1}{\sqrt{n \pi}} \cdot \frac{\Gamma\big((n+1)/2\big)}{\Gamma(n/2)} \cdot \left(1 + \frac{x^2}{n} \right)^{-(n+1)/2} - \text{ .} \] +\end{formula} \indexlibraryglobal{student_t_distribution}% \indexlibrarymember{result_type}{student_t_distribution}% @@ -5815,8 +6281,10 @@ A \tcode{discrete_distribution} random number distribution produces random integers $i$, $0 \leq i < n$, distributed according to -the discrete probability function% -\[ P(i \,|\, p_0, \dotsc, p_{n-1}) = p_i \text{ .} \] +the discrete probability function in \eqref{rand.dist.samp.discrete}. +\begin{formula}{rand.dist.samp.discrete} +P(i \,|\, p_0, \dotsc, p_{n-1}) = p_i +\end{formula} \pnum Unless specified otherwise, @@ -5917,7 +6385,7 @@ \pnum \effects Constructs a \tcode{discrete_distribution} object -with probabilities given by the formula above. +with probabilities given by the \eqref{rand.dist.samp.discrete}. \end{itemdescr} @@ -5994,9 +6462,11 @@ $b_0 \leq x < b_n$, uniformly distributed over each subinterval $[ b_i, b_{i+1} )$ -according to the probability density function -\[ p(x \,|\, b_0, \dotsc, b_n, \; \rho_0, \dotsc, \rho_{n-1}) = \rho_i - \text{ , for $b_i \le x < b_{i+1}$.} \] +according to the probability density function in \eqref{rand.dist.samp.pconst}. +\begin{formula}{rand.dist.samp.pconst} +p(x \,|\, b_0, \dotsc, b_n, \; \rho_0, \dotsc, \rho_{n-1}) = \rho_i + \text{ , for $b_i \le x < b_{i+1}$} +\end{formula} \pnum The $n + 1$ distribution parameters $b_i$, @@ -6085,8 +6555,8 @@ \indexlibraryctor{piecewise_constant_distribution}% \begin{itemdecl} template - piecewise_constant_distribution(InputIteratorB firstB, InputIteratorB lastB, - InputIteratorW firstW); + piecewise_constant_distribution(InputIteratorB firstB, InputIteratorB lastB, + InputIteratorW firstW); \end{itemdecl} \begin{itemdescr} @@ -6127,7 +6597,7 @@ \indexlibraryctor{piecewise_constant_distribution}% \begin{itemdecl} template - piecewise_constant_distribution(initializer_list bl, UnaryOperation fw); + piecewise_constant_distribution(initializer_list bl, UnaryOperation fw); \end{itemdecl} \begin{itemdescr} @@ -6161,7 +6631,7 @@ \indexlibraryctor{piecewise_constant_distribution}% \begin{itemdecl} template - piecewise_constant_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw); + piecewise_constant_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw); \end{itemdecl} \begin{itemdescr} @@ -6230,11 +6700,13 @@ $b_0 \leq x < b_n$, distributed over each subinterval $[b_i, b_{i+1})$ -according to the probability density function -\[ p(x \,|\, b_0, \dotsc, b_n, \; \rho_0, \dotsc, \rho_n) +according to the probability density function in \eqref{rand.dist.samp.plinear}. +\begin{formula}{rand.dist.samp.plinear} +p(x \,|\, b_0, \dotsc, b_n, \; \rho_0, \dotsc, \rho_n) = \rho_{i} \cdot {\frac{b_{i+1} - x}{b_{i+1} - b_i}} + \rho_{i+1} \cdot {\frac{x - b_i}{b_{i+1} - b_i}} - \text{ , for $b_i \le x < b_{i+1}$.} \] + \text{ , for $b_i \le x < b_{i+1}$.} +\end{formula} \pnum The $n + 1$ distribution parameters $b_i$, @@ -6318,14 +6790,19 @@ \indexlibraryctor{piecewise_linear_distribution} \begin{itemdecl} template - piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB, - InputIteratorW firstW); + piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB, + InputIteratorW firstW); \end{itemdecl} \begin{itemdescr} \pnum \mandates -\tcode{is_invocable_r_v} is \tcode{true}. +Both of +\begin{itemize} +\item{\tcode{is_convertible_v::value_type, double>}} +\item{\tcode{is_convertible_v::value_type, double>}} +\end{itemize} +are \tcode{true}. \pnum \expects @@ -6355,7 +6832,7 @@ \indexlibraryctor{piecewise_linear_distribution}% \begin{itemdecl} template - piecewise_linear_distribution(initializer_list bl, UnaryOperation fw); + piecewise_linear_distribution(initializer_list bl, UnaryOperation fw); \end{itemdecl} \begin{itemdescr} @@ -6389,7 +6866,7 @@ \indexlibraryctor{piecewise_linear_distribution}% \begin{itemdecl} template - piecewise_linear_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw); + piecewise_linear_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw); \end{itemdecl} \begin{itemdescr} @@ -7098,13 +7575,13 @@ \indexlibrarymember{operator[]}{valarray}% \begin{itemdecl} -const T& operator[](size_t n) const; +const T& operator[](size_t n) const; T& operator[](size_t n); \end{itemdecl} \begin{itemdescr} \pnum -\expects +\hardexpects \tcode{n < size()} is \tcode{true}. \pnum @@ -8727,23 +9204,6 @@ \rSec2[cmath.syn]{Header \tcode{} synopsis} \indexheader{cmath}% -\indexlibraryglobal{FP_FAST_FMA}% -\indexlibraryglobal{FP_FAST_FMAF}% -\indexlibraryglobal{FP_FAST_FMAL}% -\indexlibraryglobal{FP_ILOGB0}% -\indexlibraryglobal{FP_ILOGBNAN}% -\indexlibraryglobal{FP_INFINITE}% -\indexlibraryglobal{FP_NAN}% -\indexlibraryglobal{FP_NORMAL}% -\indexlibraryglobal{FP_SUBNORMAL}% -\indexlibraryglobal{FP_ZERO}% -\indexlibraryglobal{HUGE_VAL}% -\indexlibraryglobal{HUGE_VALF}% -\indexlibraryglobal{HUGE_VALL}% -\indexlibraryglobal{INFINITY}% -\indexlibraryglobal{MATH_ERREXCEPT}% -\indexlibraryglobal{MATH_ERRNO}% -\indexlibraryglobal{NAN}% \indexlibraryglobal{abs}% \indexlibraryglobal{acos}% \indexlibraryglobal{acosf}% @@ -8872,7 +9332,6 @@ \indexlibraryglobal{lround}% \indexlibraryglobal{lroundf}% \indexlibraryglobal{lroundl}% -\indexlibraryglobal{math_errhandling}% \indexlibraryglobal{modf}% \indexlibraryglobal{modff}% \indexlibraryglobal{modfl}% @@ -8932,398 +9391,396 @@ \indexlibraryglobal{truncf}% \indexlibraryglobal{truncl}% \begin{codeblock} +#define @\libmacro{HUGE_VAL}@ @\seebelow@ +#define @\libmacro{HUGE_VALF}@ @\seebelow@ +#define @\libmacro{HUGE_VALL}@ @\seebelow@ +#define @\libmacro{INFINITY}@ @\seebelow@ +#define @\libmacro{NAN}@ @\seebelow@ +#define @\libmacro{FP_INFINITE}@ @\seebelow@ +#define @\libmacro{FP_NAN}@ @\seebelow@ +#define @\libmacro{FP_NORMAL}@ @\seebelow@ +#define @\libmacro{FP_SUBNORMAL}@ @\seebelow@ +#define @\libmacro{FP_ZERO}@ @\seebelow@ +#define @\libmacro{FP_FAST_FMA}@ @\seebelow@ +#define @\libmacro{FP_FAST_FMAF}@ @\seebelow@ +#define @\libmacro{FP_FAST_FMAL}@ @\seebelow@ +#define @\libmacro{FP_ILOGB0}@ @\seebelow@ +#define @\libmacro{FP_ILOGBNAN}@ @\seebelow@ +#define @\libmacro{MATH_ERRNO}@ @\seebelow@ +#define @\libmacro{MATH_ERREXCEPT}@ @\seebelow@ + +#define @\libmacro{math_errhandling}@ @\seebelow@ + namespace std { using float_t = @\seebelow@; using double_t = @\seebelow@; -} - -#define HUGE_VAL @\seebelow@ -#define HUGE_VALF @\seebelow@ -#define HUGE_VALL @\seebelow@ -#define INFINITY @\seebelow@ -#define NAN @\seebelow@ -#define FP_INFINITE @\seebelow@ -#define FP_NAN @\seebelow@ -#define FP_NORMAL @\seebelow@ -#define FP_SUBNORMAL @\seebelow@ -#define FP_ZERO @\seebelow@ -#define FP_FAST_FMA @\seebelow@ -#define FP_FAST_FMAF @\seebelow@ -#define FP_FAST_FMAL @\seebelow@ -#define FP_ILOGB0 @\seebelow@ -#define FP_ILOGBNAN @\seebelow@ -#define MATH_ERRNO @\seebelow@ -#define MATH_ERREXCEPT @\seebelow@ - -#define math_errhandling @\seebelow@ -namespace std { - constexpr @\placeholder{floating-point-type}@ acos(@\placeholder{floating-point-type}@ x); - constexpr float acosf(float x); - constexpr long double acosl(long double x); + constexpr @\placeholdernc{floating-point-type}@ acos(@\placeholdernc{floating-point-type}@ x); + constexpr float acosf(float x); + constexpr long double acosl(long double x); - constexpr @\placeholder{floating-point-type}@ asin(@\placeholder{floating-point-type}@ x); - constexpr float asinf(float x); - constexpr long double asinl(long double x); + constexpr @\placeholdernc{floating-point-type}@ asin(@\placeholdernc{floating-point-type}@ x); + constexpr float asinf(float x); + constexpr long double asinl(long double x); - constexpr @\placeholder{floating-point-type}@ atan(@\placeholder{floating-point-type}@ x); - constexpr float atanf(float x); - constexpr long double atanl(long double x); + constexpr @\placeholdernc{floating-point-type}@ atan(@\placeholdernc{floating-point-type}@ x); + constexpr float atanf(float x); + constexpr long double atanl(long double x); - constexpr @\placeholder{floating-point-type}@ atan2(@\placeholder{floating-point-type}@ y, @\placeholder{floating-point-type}@ x); - constexpr float atan2f(float y, float x); - constexpr long double atan2l(long double y, long double x); + constexpr @\placeholdernc{floating-point-type}@ atan2(@\placeholdernc{floating-point-type}@ y, @\placeholdernc{floating-point-type}@ x); + constexpr float atan2f(float y, float x); + constexpr long double atan2l(long double y, long double x); - constexpr @\placeholder{floating-point-type}@ cos(@\placeholder{floating-point-type}@ x); - constexpr float cosf(float x); - constexpr long double cosl(long double x); + constexpr @\placeholdernc{floating-point-type}@ cos(@\placeholdernc{floating-point-type}@ x); + constexpr float cosf(float x); + constexpr long double cosl(long double x); - constexpr @\placeholder{floating-point-type}@ sin(@\placeholder{floating-point-type}@ x); - constexpr float sinf(float x); - constexpr long double sinl(long double x); + constexpr @\placeholdernc{floating-point-type}@ sin(@\placeholdernc{floating-point-type}@ x); + constexpr float sinf(float x); + constexpr long double sinl(long double x); - constexpr @\placeholder{floating-point-type}@ tan(@\placeholder{floating-point-type}@ x); - constexpr float tanf(float x); - constexpr long double tanl(long double x); + constexpr @\placeholdernc{floating-point-type}@ tan(@\placeholdernc{floating-point-type}@ x); + constexpr float tanf(float x); + constexpr long double tanl(long double x); - constexpr @\placeholder{floating-point-type}@ acosh(@\placeholder{floating-point-type}@ x); - constexpr float acoshf(float x); - constexpr long double acoshl(long double x); + constexpr @\placeholdernc{floating-point-type}@ acosh(@\placeholdernc{floating-point-type}@ x); + constexpr float acoshf(float x); + constexpr long double acoshl(long double x); - constexpr @\placeholder{floating-point-type}@ asinh(@\placeholder{floating-point-type}@ x); - constexpr float asinhf(float x); - constexpr long double asinhl(long double x); + constexpr @\placeholdernc{floating-point-type}@ asinh(@\placeholdernc{floating-point-type}@ x); + constexpr float asinhf(float x); + constexpr long double asinhl(long double x); - constexpr @\placeholder{floating-point-type}@ atanh(@\placeholder{floating-point-type}@ x); - constexpr float atanhf(float x); - constexpr long double atanhl(long double x); + constexpr @\placeholdernc{floating-point-type}@ atanh(@\placeholdernc{floating-point-type}@ x); + constexpr float atanhf(float x); + constexpr long double atanhl(long double x); - constexpr @\placeholder{floating-point-type}@ cosh(@\placeholder{floating-point-type}@ x); - constexpr float coshf(float x); - constexpr long double coshl(long double x); + constexpr @\placeholdernc{floating-point-type}@ cosh(@\placeholdernc{floating-point-type}@ x); + constexpr float coshf(float x); + constexpr long double coshl(long double x); - constexpr @\placeholder{floating-point-type}@ sinh(@\placeholder{floating-point-type}@ x); - constexpr float sinhf(float x); - constexpr long double sinhl(long double x); + constexpr @\placeholdernc{floating-point-type}@ sinh(@\placeholdernc{floating-point-type}@ x); + constexpr float sinhf(float x); + constexpr long double sinhl(long double x); - constexpr @\placeholder{floating-point-type}@ tanh(@\placeholder{floating-point-type}@ x); - constexpr float tanhf(float x); - constexpr long double tanhl(long double x); + constexpr @\placeholdernc{floating-point-type}@ tanh(@\placeholdernc{floating-point-type}@ x); + constexpr float tanhf(float x); + constexpr long double tanhl(long double x); - constexpr @\placeholder{floating-point-type}@ exp(@\placeholder{floating-point-type}@ x); - constexpr float expf(float x); - constexpr long double expl(long double x); + constexpr @\placeholdernc{floating-point-type}@ exp(@\placeholdernc{floating-point-type}@ x); + constexpr float expf(float x); + constexpr long double expl(long double x); - constexpr @\placeholder{floating-point-type}@ exp2(@\placeholder{floating-point-type}@ x); - constexpr float exp2f(float x); - constexpr long double exp2l(long double x); + constexpr @\placeholdernc{floating-point-type}@ exp2(@\placeholdernc{floating-point-type}@ x); + constexpr float exp2f(float x); + constexpr long double exp2l(long double x); - constexpr @\placeholder{floating-point-type}@ expm1(@\placeholder{floating-point-type}@ x); - constexpr float expm1f(float x); - constexpr long double expm1l(long double x); + constexpr @\placeholdernc{floating-point-type}@ expm1(@\placeholdernc{floating-point-type}@ x); + constexpr float expm1f(float x); + constexpr long double expm1l(long double x); - constexpr @\placeholder{floating-point-type}@ frexp(@\placeholder{floating-point-type}@ value, int* exp); - constexpr float frexpf(float value, int* exp); - constexpr long double frexpl(long double value, int* exp); + constexpr @\placeholdernc{floating-point-type}@ frexp(@\placeholdernc{floating-point-type}@ value, int* exp); + constexpr float frexpf(float value, int* exp); + constexpr long double frexpl(long double value, int* exp); - constexpr int ilogb(@\placeholder{floating-point-type}@ x); + constexpr int ilogb(@\placeholdernc{floating-point-type}@ x); constexpr int ilogbf(float x); constexpr int ilogbl(long double x); - constexpr @\placeholder{floating-point-type}@ ldexp(@\placeholder{floating-point-type}@ x, int exp); - constexpr float ldexpf(float x, int exp); - constexpr long double ldexpl(long double x, int exp); + constexpr @\placeholdernc{floating-point-type}@ ldexp(@\placeholdernc{floating-point-type}@ x, int exp); + constexpr float ldexpf(float x, int exp); + constexpr long double ldexpl(long double x, int exp); - constexpr @\placeholder{floating-point-type}@ log(@\placeholder{floating-point-type}@ x); - constexpr float logf(float x); - constexpr long double logl(long double x); + constexpr @\placeholdernc{floating-point-type}@ log(@\placeholdernc{floating-point-type}@ x); + constexpr float logf(float x); + constexpr long double logl(long double x); - constexpr @\placeholder{floating-point-type}@ log10(@\placeholder{floating-point-type}@ x); - constexpr float log10f(float x); - constexpr long double log10l(long double x); + constexpr @\placeholdernc{floating-point-type}@ log10(@\placeholdernc{floating-point-type}@ x); + constexpr float log10f(float x); + constexpr long double log10l(long double x); - constexpr @\placeholder{floating-point-type}@ log1p(@\placeholder{floating-point-type}@ x); - constexpr float log1pf(float x); - constexpr long double log1pl(long double x); + constexpr @\placeholdernc{floating-point-type}@ log1p(@\placeholdernc{floating-point-type}@ x); + constexpr float log1pf(float x); + constexpr long double log1pl(long double x); - constexpr @\placeholder{floating-point-type}@ log2(@\placeholder{floating-point-type}@ x); - constexpr float log2f(float x); - constexpr long double log2l(long double x); + constexpr @\placeholdernc{floating-point-type}@ log2(@\placeholdernc{floating-point-type}@ x); + constexpr float log2f(float x); + constexpr long double log2l(long double x); - constexpr @\placeholder{floating-point-type}@ logb(@\placeholder{floating-point-type}@ x); - constexpr float logbf(float x); - constexpr long double logbl(long double x); + constexpr @\placeholdernc{floating-point-type}@ logb(@\placeholdernc{floating-point-type}@ x); + constexpr float logbf(float x); + constexpr long double logbl(long double x); - constexpr @\placeholder{floating-point-type}@ modf(@\placeholder{floating-point-type}@ value, @\placeholder{floating-point-type}@* iptr); - constexpr float modff(float value, float* iptr); - constexpr long double modfl(long double value, long double* iptr); + constexpr @\placeholdernc{floating-point-type}@ modf(@\placeholdernc{floating-point-type}@ value, @\placeholdernc{floating-point-type}@* iptr); + constexpr float modff(float value, float* iptr); + constexpr long double modfl(long double value, long double* iptr); - constexpr @\placeholder{floating-point-type}@ scalbn(@\placeholder{floating-point-type}@ x, int n); - constexpr float scalbnf(float x, int n); - constexpr long double scalbnl(long double x, int n); + constexpr @\placeholdernc{floating-point-type}@ scalbn(@\placeholdernc{floating-point-type}@ x, int n); + constexpr float scalbnf(float x, int n); + constexpr long double scalbnl(long double x, int n); - constexpr @\placeholder{floating-point-type}@ scalbln(@\placeholder{floating-point-type}@ x, long int n); - constexpr float scalblnf(float x, long int n); - constexpr long double scalblnl(long double x, long int n); + constexpr @\placeholdernc{floating-point-type}@ scalbln(@\placeholdernc{floating-point-type}@ x, long int n); + constexpr float scalblnf(float x, long int n); + constexpr long double scalblnl(long double x, long int n); - constexpr @\placeholder{floating-point-type}@ cbrt(@\placeholder{floating-point-type}@ x); - constexpr float cbrtf(float x); - constexpr long double cbrtl(long double x); + constexpr @\placeholdernc{floating-point-type}@ cbrt(@\placeholdernc{floating-point-type}@ x); + constexpr float cbrtf(float x); + constexpr long double cbrtl(long double x); // \ref{c.math.abs}, absolute values - constexpr int abs(int j); // freestanding - constexpr long int abs(long int j); // freestanding - constexpr long long int abs(long long int j); // freestanding - constexpr @\placeholder{floating-point-type}@ abs(@\placeholder{floating-point-type}@ j); // freestanding-deleted + constexpr int abs(int j); // freestanding + constexpr long int abs(long int j); // freestanding + constexpr long long int abs(long long int j); // freestanding + constexpr @\placeholdernc{floating-point-type}@ abs(@\placeholdernc{floating-point-type}@ j); // freestanding-deleted - constexpr @\placeholder{floating-point-type}@ fabs(@\placeholder{floating-point-type}@ x); - constexpr float fabsf(float x); - constexpr long double fabsl(long double x); + constexpr @\placeholdernc{floating-point-type}@ fabs(@\placeholdernc{floating-point-type}@ x); + constexpr float fabsf(float x); + constexpr long double fabsl(long double x); - constexpr @\placeholder{floating-point-type}@ hypot(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float hypotf(float x, float y); - constexpr long double hypotl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ hypot(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float hypotf(float x, float y); + constexpr long double hypotl(long double x, long double y); // \ref{c.math.hypot3}, three-dimensional hypotenuse - constexpr @\placeholder{floating-point-type}@ hypot(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y, - @\placeholder{floating-point-type}@ z); + constexpr @\placeholdernc{floating-point-type}@ hypot(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y, + @\placeholdernc{floating-point-type}@ z); - constexpr @\placeholder{floating-point-type}@ pow(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float powf(float x, float y); - constexpr long double powl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ pow(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float powf(float x, float y); + constexpr long double powl(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ sqrt(@\placeholder{floating-point-type}@ x); - constexpr float sqrtf(float x); - constexpr long double sqrtl(long double x); + constexpr @\placeholdernc{floating-point-type}@ sqrt(@\placeholdernc{floating-point-type}@ x); + constexpr float sqrtf(float x); + constexpr long double sqrtl(long double x); - constexpr @\placeholder{floating-point-type}@ erf(@\placeholder{floating-point-type}@ x); - constexpr float erff(float x); - constexpr long double erfl(long double x); + constexpr @\placeholdernc{floating-point-type}@ erf(@\placeholdernc{floating-point-type}@ x); + constexpr float erff(float x); + constexpr long double erfl(long double x); - constexpr @\placeholder{floating-point-type}@ erfc(@\placeholder{floating-point-type}@ x); - constexpr float erfcf(float x); - constexpr long double erfcl(long double x); + constexpr @\placeholdernc{floating-point-type}@ erfc(@\placeholdernc{floating-point-type}@ x); + constexpr float erfcf(float x); + constexpr long double erfcl(long double x); - constexpr @\placeholder{floating-point-type}@ lgamma(@\placeholder{floating-point-type}@ x); - constexpr float lgammaf(float x); - constexpr long double lgammal(long double x); + constexpr @\placeholdernc{floating-point-type}@ lgamma(@\placeholdernc{floating-point-type}@ x); + constexpr float lgammaf(float x); + constexpr long double lgammal(long double x); - constexpr @\placeholder{floating-point-type}@ tgamma(@\placeholder{floating-point-type}@ x); - constexpr float tgammaf(float x); - constexpr long double tgammal(long double x); + constexpr @\placeholdernc{floating-point-type}@ tgamma(@\placeholdernc{floating-point-type}@ x); + constexpr float tgammaf(float x); + constexpr long double tgammal(long double x); - constexpr @\placeholder{floating-point-type}@ ceil(@\placeholder{floating-point-type}@ x); - constexpr float ceilf(float x); - constexpr long double ceill(long double x); + constexpr @\placeholdernc{floating-point-type}@ ceil(@\placeholdernc{floating-point-type}@ x); + constexpr float ceilf(float x); + constexpr long double ceill(long double x); - constexpr @\placeholder{floating-point-type}@ floor(@\placeholder{floating-point-type}@ x); - constexpr float floorf(float x); - constexpr long double floorl(long double x); + constexpr @\placeholdernc{floating-point-type}@ floor(@\placeholdernc{floating-point-type}@ x); + constexpr float floorf(float x); + constexpr long double floorl(long double x); - @\placeholder{floating-point-type}@ nearbyint(@\placeholder{floating-point-type}@ x); - float nearbyintf(float x); - long double nearbyintl(long double x); + @\placeholdernc{floating-point-type}@ nearbyint(@\placeholdernc{floating-point-type}@ x); + float nearbyintf(float x); + long double nearbyintl(long double x); - @\placeholder{floating-point-type}@ rint(@\placeholder{floating-point-type}@ x); - float rintf(float x); - long double rintl(long double x); + @\placeholdernc{floating-point-type}@ rint(@\placeholdernc{floating-point-type}@ x); + float rintf(float x); + long double rintl(long double x); - long int lrint(@\placeholder{floating-point-type}@ x); + long int lrint(@\placeholdernc{floating-point-type}@ x); long int lrintf(float x); long int lrintl(long double x); - long long int llrint(@\placeholder{floating-point-type}@ x); + long long int llrint(@\placeholdernc{floating-point-type}@ x); long long int llrintf(float x); long long int llrintl(long double x); - constexpr @\placeholder{floating-point-type}@ round(@\placeholder{floating-point-type}@ x); - constexpr float roundf(float x); - constexpr long double roundl(long double x); + constexpr @\placeholdernc{floating-point-type}@ round(@\placeholdernc{floating-point-type}@ x); + constexpr float roundf(float x); + constexpr long double roundl(long double x); - constexpr long int lround(@\placeholder{floating-point-type}@ x); + constexpr long int lround(@\placeholdernc{floating-point-type}@ x); constexpr long int lroundf(float x); constexpr long int lroundl(long double x); - constexpr long long int llround(@\placeholder{floating-point-type}@ x); + constexpr long long int llround(@\placeholdernc{floating-point-type}@ x); constexpr long long int llroundf(float x); constexpr long long int llroundl(long double x); - constexpr @\placeholder{floating-point-type}@ trunc(@\placeholder{floating-point-type}@ x); - constexpr float truncf(float x); - constexpr long double truncl(long double x); + constexpr @\placeholdernc{floating-point-type}@ trunc(@\placeholdernc{floating-point-type}@ x); + constexpr float truncf(float x); + constexpr long double truncl(long double x); - constexpr @\placeholder{floating-point-type}@ fmod(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float fmodf(float x, float y); - constexpr long double fmodl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ fmod(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float fmodf(float x, float y); + constexpr long double fmodl(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ remainder(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float remainderf(float x, float y); - constexpr long double remainderl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ remainder(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float remainderf(float x, float y); + constexpr long double remainderl(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ remquo(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y, int* quo); - constexpr float remquof(float x, float y, int* quo); - constexpr long double remquol(long double x, long double y, int* quo); + constexpr @\placeholdernc{floating-point-type}@ remquo(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y, int* quo); + constexpr float remquof(float x, float y, int* quo); + constexpr long double remquol(long double x, long double y, int* quo); - constexpr @\placeholder{floating-point-type}@ copysign(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float copysignf(float x, float y); - constexpr long double copysignl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ copysign(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float copysignf(float x, float y); + constexpr long double copysignl(long double x, long double y); - double nan(const char* tagp); - float nanf(const char* tagp); + double nan(const char* tagp); + float nanf(const char* tagp); long double nanl(const char* tagp); - constexpr @\placeholder{floating-point-type}@ nextafter(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float nextafterf(float x, float y); - constexpr long double nextafterl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ nextafter(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float nextafterf(float x, float y); + constexpr long double nextafterl(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ nexttoward(@\placeholder{floating-point-type}@ x, long double y); - constexpr float nexttowardf(float x, long double y); - constexpr long double nexttowardl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ nexttoward(@\placeholdernc{floating-point-type}@ x, long double y); + constexpr float nexttowardf(float x, long double y); + constexpr long double nexttowardl(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ fdim(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float fdimf(float x, float y); - constexpr long double fdiml(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ fdim(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float fdimf(float x, float y); + constexpr long double fdiml(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ fmax(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float fmaxf(float x, float y); - constexpr long double fmaxl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ fmax(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float fmaxf(float x, float y); + constexpr long double fmaxl(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ fmin(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr float fminf(float x, float y); - constexpr long double fminl(long double x, long double y); + constexpr @\placeholdernc{floating-point-type}@ fmin(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr float fminf(float x, float y); + constexpr long double fminl(long double x, long double y); - constexpr @\placeholder{floating-point-type}@ fma(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y, - @\placeholder{floating-point-type}@ z); - constexpr float fmaf(float x, float y, float z); - constexpr long double fmal(long double x, long double y, long double z); + constexpr @\placeholdernc{floating-point-type}@ fma(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y, + @\placeholdernc{floating-point-type}@ z); + constexpr float fmaf(float x, float y, float z); + constexpr long double fmal(long double x, long double y, long double z); // \ref{c.math.lerp}, linear interpolation - constexpr @\placeholder{floating-point-type}@ lerp(@\placeholder{floating-point-type}@ a, @\placeholder{floating-point-type}@ b, - @\placeholder{floating-point-type}@ t) noexcept; + constexpr @\placeholdernc{floating-point-type}@ lerp(@\placeholdernc{floating-point-type}@ a, @\placeholdernc{floating-point-type}@ b, + @\placeholdernc{floating-point-type}@ t) noexcept; // \ref{c.math.fpclass}, classification / comparison functions - constexpr int fpclassify(@\placeholder{floating-point-type}@ x); - constexpr bool isfinite(@\placeholder{floating-point-type}@ x); - constexpr bool isinf(@\placeholder{floating-point-type}@ x); - constexpr bool isnan(@\placeholder{floating-point-type}@ x); - constexpr bool isnormal(@\placeholder{floating-point-type}@ x); - constexpr bool signbit(@\placeholder{floating-point-type}@ x); - constexpr bool isgreater(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr bool isgreaterequal(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr bool isless(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr bool islessequal(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr bool islessgreater(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - constexpr bool isunordered(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); + constexpr int fpclassify(@\placeholdernc{floating-point-type}@ x); + constexpr bool isfinite(@\placeholdernc{floating-point-type}@ x); + constexpr bool isinf(@\placeholdernc{floating-point-type}@ x); + constexpr bool isnan(@\placeholdernc{floating-point-type}@ x); + constexpr bool isnormal(@\placeholdernc{floating-point-type}@ x); + constexpr bool signbit(@\placeholdernc{floating-point-type}@ x); + constexpr bool isgreater(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr bool isgreaterequal(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr bool isless(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr bool islessequal(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr bool islessgreater(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + constexpr bool isunordered(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); // \ref{sf.cmath}, mathematical special functions // \ref{sf.cmath.assoc.laguerre}, associated Laguerre polynomials - @\placeholder{floating-point-type}@ assoc_laguerre(unsigned n, unsigned m, @\placeholder{floating-point-type}@ x); - float assoc_laguerref(unsigned n, unsigned m, float x); - long double assoc_laguerrel(unsigned n, unsigned m, long double x); + @\placeholdernc{floating-point-type}@ assoc_laguerre(unsigned n, unsigned m, @\placeholdernc{floating-point-type}@ x); + float assoc_laguerref(unsigned n, unsigned m, float x); + long double assoc_laguerrel(unsigned n, unsigned m, long double x); // \ref{sf.cmath.assoc.legendre}, associated Legendre functions - @\placeholder{floating-point-type}@ assoc_legendre(unsigned l, unsigned m, @\placeholder{floating-point-type}@ x); - float assoc_legendref(unsigned l, unsigned m, float x); - long double assoc_legendrel(unsigned l, unsigned m, long double x); + @\placeholdernc{floating-point-type}@ assoc_legendre(unsigned l, unsigned m, @\placeholdernc{floating-point-type}@ x); + float assoc_legendref(unsigned l, unsigned m, float x); + long double assoc_legendrel(unsigned l, unsigned m, long double x); // \ref{sf.cmath.beta}, beta function - @\placeholder{floating-point-type}@ beta(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); - float betaf(float x, float y); - long double betal(long double x, long double y); + @\placeholdernc{floating-point-type}@ beta(@\placeholdernc{floating-point-type}@ x, @\placeholdernc{floating-point-type}@ y); + float betaf(float x, float y); + long double betal(long double x, long double y); // \ref{sf.cmath.comp.ellint.1}, complete elliptic integral of the first kind - @\placeholder{floating-point-type}@ comp_ellint_1(@\placeholder{floating-point-type}@ k); - float comp_ellint_1f(float k); - long double comp_ellint_1l(long double k); + @\placeholdernc{floating-point-type}@ comp_ellint_1(@\placeholdernc{floating-point-type}@ k); + float comp_ellint_1f(float k); + long double comp_ellint_1l(long double k); // \ref{sf.cmath.comp.ellint.2}, complete elliptic integral of the second kind - @\placeholder{floating-point-type}@ comp_ellint_2(@\placeholder{floating-point-type}@ k); - float comp_ellint_2f(float k); - long double comp_ellint_2l(long double k); + @\placeholdernc{floating-point-type}@ comp_ellint_2(@\placeholdernc{floating-point-type}@ k); + float comp_ellint_2f(float k); + long double comp_ellint_2l(long double k); // \ref{sf.cmath.comp.ellint.3}, complete elliptic integral of the third kind - @\placeholder{floating-point-type}@ comp_ellint_3(@\placeholder{floating-point-type}@ k, @\placeholder{floating-point-type}@ nu); - float comp_ellint_3f(float k, float nu); - long double comp_ellint_3l(long double k, long double nu); + @\placeholdernc{floating-point-type}@ comp_ellint_3(@\placeholdernc{floating-point-type}@ k, @\placeholdernc{floating-point-type}@ nu); + float comp_ellint_3f(float k, float nu); + long double comp_ellint_3l(long double k, long double nu); // \ref{sf.cmath.cyl.bessel.i}, regular modified cylindrical Bessel functions - @\placeholder{floating-point-type}@ cyl_bessel_i(@\placeholder{floating-point-type}@ nu, @\placeholder{floating-point-type}@ x); - float cyl_bessel_if(float nu, float x); - long double cyl_bessel_il(long double nu, long double x); + @\placeholdernc{floating-point-type}@ cyl_bessel_i(@\placeholdernc{floating-point-type}@ nu, @\placeholdernc{floating-point-type}@ x); + float cyl_bessel_if(float nu, float x); + long double cyl_bessel_il(long double nu, long double x); // \ref{sf.cmath.cyl.bessel.j}, cylindrical Bessel functions of the first kind - @\placeholder{floating-point-type}@ cyl_bessel_j(@\placeholder{floating-point-type}@ nu, @\placeholder{floating-point-type}@ x); - float cyl_bessel_jf(float nu, float x); - long double cyl_bessel_jl(long double nu, long double x); + @\placeholdernc{floating-point-type}@ cyl_bessel_j(@\placeholdernc{floating-point-type}@ nu, @\placeholdernc{floating-point-type}@ x); + float cyl_bessel_jf(float nu, float x); + long double cyl_bessel_jl(long double nu, long double x); // \ref{sf.cmath.cyl.bessel.k}, irregular modified cylindrical Bessel functions - @\placeholder{floating-point-type}@ cyl_bessel_k(@\placeholder{floating-point-type}@ nu, @\placeholder{floating-point-type}@ x); - float cyl_bessel_kf(float nu, float x); - long double cyl_bessel_kl(long double nu, long double x); + @\placeholdernc{floating-point-type}@ cyl_bessel_k(@\placeholdernc{floating-point-type}@ nu, @\placeholdernc{floating-point-type}@ x); + float cyl_bessel_kf(float nu, float x); + long double cyl_bessel_kl(long double nu, long double x); // \ref{sf.cmath.cyl.neumann}, cylindrical Neumann functions // cylindrical Bessel functions of the second kind - @\placeholder{floating-point-type}@ cyl_neumann(@\placeholder{floating-point-type}@ nu, @\placeholder{floating-point-type}@ x); - float cyl_neumannf(float nu, float x); - long double cyl_neumannl(long double nu, long double x); + @\placeholdernc{floating-point-type}@ cyl_neumann(@\placeholdernc{floating-point-type}@ nu, @\placeholdernc{floating-point-type}@ x); + float cyl_neumannf(float nu, float x); + long double cyl_neumannl(long double nu, long double x); // \ref{sf.cmath.ellint.1}, incomplete elliptic integral of the first kind - @\placeholder{floating-point-type}@ ellint_1(@\placeholder{floating-point-type}@ k, @\placeholder{floating-point-type}@ phi); - float ellint_1f(float k, float phi); - long double ellint_1l(long double k, long double phi); + @\placeholdernc{floating-point-type}@ ellint_1(@\placeholdernc{floating-point-type}@ k, @\placeholdernc{floating-point-type}@ phi); + float ellint_1f(float k, float phi); + long double ellint_1l(long double k, long double phi); // \ref{sf.cmath.ellint.2}, incomplete elliptic integral of the second kind - @\placeholder{floating-point-type}@ ellint_2(@\placeholder{floating-point-type}@ k, @\placeholder{floating-point-type}@ phi); - float ellint_2f(float k, float phi); - long double ellint_2l(long double k, long double phi); + @\placeholdernc{floating-point-type}@ ellint_2(@\placeholdernc{floating-point-type}@ k, @\placeholdernc{floating-point-type}@ phi); + float ellint_2f(float k, float phi); + long double ellint_2l(long double k, long double phi); // \ref{sf.cmath.ellint.3}, incomplete elliptic integral of the third kind - @\placeholder{floating-point-type}@ ellint_3(@\placeholder{floating-point-type}@ k, @\placeholder{floating-point-type}@ nu, - @\placeholder{floating-point-type}@ phi); - float ellint_3f(float k, float nu, float phi); - long double ellint_3l(long double k, long double nu, long double phi); + @\placeholdernc{floating-point-type}@ ellint_3(@\placeholdernc{floating-point-type}@ k, @\placeholdernc{floating-point-type}@ nu, + @\placeholdernc{floating-point-type}@ phi); + float ellint_3f(float k, float nu, float phi); + long double ellint_3l(long double k, long double nu, long double phi); // \ref{sf.cmath.expint}, exponential integral - @\placeholder{floating-point-type}@ expint(@\placeholder{floating-point-type}@ x); - float expintf(float x); - long double expintl(long double x); + @\placeholdernc{floating-point-type}@ expint(@\placeholdernc{floating-point-type}@ x); + float expintf(float x); + long double expintl(long double x); // \ref{sf.cmath.hermite}, Hermite polynomials - @\placeholder{floating-point-type}@ hermite(unsigned n, @\placeholder{floating-point-type}@ x); - float hermitef(unsigned n, float x); - long double hermitel(unsigned n, long double x); + @\placeholdernc{floating-point-type}@ hermite(unsigned n, @\placeholdernc{floating-point-type}@ x); + float hermitef(unsigned n, float x); + long double hermitel(unsigned n, long double x); // \ref{sf.cmath.laguerre}, Laguerre polynomials - @\placeholder{floating-point-type}@ laguerre(unsigned n, @\placeholder{floating-point-type}@ x); - float laguerref(unsigned n, float x); - long double laguerrel(unsigned n, long double x); + @\placeholdernc{floating-point-type}@ laguerre(unsigned n, @\placeholdernc{floating-point-type}@ x); + float laguerref(unsigned n, float x); + long double laguerrel(unsigned n, long double x); // \ref{sf.cmath.legendre}, Legendre polynomials - @\placeholder{floating-point-type}@ legendre(unsigned l, @\placeholder{floating-point-type}@ x); - float legendref(unsigned l, float x); - long double legendrel(unsigned l, long double x); + @\placeholdernc{floating-point-type}@ legendre(unsigned l, @\placeholdernc{floating-point-type}@ x); + float legendref(unsigned l, float x); + long double legendrel(unsigned l, long double x); // \ref{sf.cmath.riemann.zeta}, Riemann zeta function - @\placeholder{floating-point-type}@ riemann_zeta(@\placeholder{floating-point-type}@ x); - float riemann_zetaf(float x); - long double riemann_zetal(long double x); + @\placeholdernc{floating-point-type}@ riemann_zeta(@\placeholdernc{floating-point-type}@ x); + float riemann_zetaf(float x); + long double riemann_zetal(long double x); // \ref{sf.cmath.sph.bessel}, spherical Bessel functions of the first kind - @\placeholder{floating-point-type}@ sph_bessel(unsigned n, @\placeholder{floating-point-type}@ x); - float sph_besself(unsigned n, float x); - long double sph_bessell(unsigned n, long double x); + @\placeholdernc{floating-point-type}@ sph_bessel(unsigned n, @\placeholdernc{floating-point-type}@ x); + float sph_besself(unsigned n, float x); + long double sph_bessell(unsigned n, long double x); // \ref{sf.cmath.sph.legendre}, spherical associated Legendre functions - @\placeholder{floating-point-type}@ sph_legendre(unsigned l, unsigned m, @\placeholder{floating-point-type}@ theta); - float sph_legendref(unsigned l, unsigned m, float theta); - long double sph_legendrel(unsigned l, unsigned m, long double theta); + @\placeholdernc{floating-point-type}@ sph_legendre(unsigned l, unsigned m, @\placeholdernc{floating-point-type}@ theta); + float sph_legendref(unsigned l, unsigned m, float theta); + long double sph_legendrel(unsigned l, unsigned m, long double theta); // \ref{sf.cmath.sph.neumann}, spherical Neumann functions; // spherical Bessel functions of the second kind - @\placeholder{floating-point-type}@ sph_neumann(unsigned n, @\placeholder{floating-point-type}@ x); - float sph_neumannf(unsigned n, float x); - long double sph_neumannl(unsigned n, long double x); + @\placeholdernc{floating-point-type}@ sph_neumann(unsigned n, @\placeholdernc{floating-point-type}@ x); + float sph_neumannf(unsigned n, float x); + long double sph_neumannl(unsigned n, long double x); } \end{codeblock} @@ -9402,7 +9859,8 @@ if \tcode{X} cannot be converted to \tcode{int} by integral promotion\iref{conv.prom}, the program is ill-formed. \begin{note} -Arguments that can be promoted to \tcode{int} are permitted for compatibility with C. +Allowing arguments that can be promoted to \tcode{int} +provides compatibility with C. \end{note} \end{itemdescr} @@ -9548,13 +10006,17 @@ \pnum \returns -\[ \mathsf{L}_n^m(x) = - (-1)^m \frac{\mathsf{d} ^ m}{\mathsf{d}x ^ m} \, \mathsf{L}_{n+m}(x) - \text{ ,\quad for $x \ge 0$,} \] -where +$\mathsf{L}_n^m(x)$, +where $\mathsf{L}_n^m$ is given by \eqref{sf.cmath.assoc.laguerre}, +$\mathsf{L}_{n+m}$ is given by \eqref{sf.cmath.laguerre}, $n$ is \tcode{n}, $m$ is \tcode{m}, and $x$ is \tcode{x}. +\begin{formula}{sf.cmath.assoc.laguerre} +\mathsf{L}_n^m(x) = + (-1)^m \frac{\mathsf{d} ^ m}{\mathsf{d}x ^ m} \, \mathsf{L}_{n+m}(x) + \text{ ,\quad for $x \ge 0$} +\end{formula} \pnum \remarks @@ -9586,13 +10048,17 @@ \pnum \returns -\[ \mathsf{P}_\ell^m(x) = (1 - x^2) ^ {m/2} \: - \frac{\mathsf{d} ^ m}{\mathsf{d}x ^ m} \, \mathsf{P}_\ell(x) - \text{ ,\quad for $|x| \le 1$,} \] -where -$l$ is \tcode{l}, +$\mathsf{P}_\ell^m(x)$, +where $\mathsf{P}_\ell^m$ is given by \eqref{sf.cmath.assoc.legendre}, +$\mathsf{P}_\ell$ is given by \eqref{sf.cmath.legendre}, +$\ell$ is \tcode{l}, $m$ is \tcode{m}, and $x$ is \tcode{x}. +\begin{formula}{sf.cmath.assoc.legendre} +\mathsf{P}_\ell^m(x) = (1 - x^2) ^ {m/2} \: + \frac{\mathsf{d} ^ m}{\mathsf{d}x ^ m} \, \mathsf{P}_\ell(x) + \text{ ,\quad for $|x| \le 1$} +\end{formula} \pnum \remarks @@ -9623,11 +10089,14 @@ \pnum \returns -\[ \mathsf{B}(x, y) = \frac{\Gamma(x) \, \Gamma(y)}{\Gamma(x + y)} - \text{ ,\quad for $x > 0$,\, $y > 0$,} \] -where +$\mathsf{B}(x, y)$, +where $\mathsf{B}$ is given by \eqref{sf.cmath.beta}, $x$ is \tcode{x} and $y$ is \tcode{y}. +\begin{formula}{sf.cmath.beta} +\mathsf{B}(x, y) = \frac{\Gamma(x) \, \Gamma(y)}{\Gamma(x + y)} + \text{ ,\quad for $x > 0$,\, $y > 0$} +\end{formula} \end{itemdescr} \rSec3[sf.cmath.comp.ellint.1]{Complete elliptic integral of the first kind}% @@ -9652,9 +10121,12 @@ \pnum \returns -\[ \mathsf{K}(k) = \mathsf{F}(k, \pi / 2) \text{ ,\quad for $|k| \le 1$,} \] -where +$\mathsf{K}(k)$, +where $\mathsf{K}$ is given by \eqref{sf.cmath.comp.ellint.1} and $k$ is \tcode{k}. +\begin{formula}{sf.cmath.comp.ellint.1} +\mathsf{K}(k) = \mathsf{F}(k, \pi / 2) \text{ ,\quad for $|k| \le 1$} +\end{formula} \pnum See also \ref{sf.cmath.ellint.1}. @@ -9682,9 +10154,12 @@ \pnum \returns -\[ \mathsf{E}(k) = \mathsf{E}(k, \pi / 2) \text{ ,\quad for $|k| \le 1$,} \] -where +$\mathsf{E}(k)$, +where $\mathsf{E}$ is given by \eqref{sf.cmath.comp.ellint.2} and $k$ is \tcode{k}. +\begin{formula}{sf.cmath.comp.ellint.2} +\mathsf{E}(k) = \mathsf{E}(k, \pi / 2) \text{ ,\quad for $|k| \le 1$} +\end{formula} \pnum See also \ref{sf.cmath.ellint.2}. @@ -9712,10 +10187,13 @@ \pnum \returns -\[ \mathsf{\Pi}(\nu, k) = \mathsf{\Pi}(\nu, k, \pi / 2) \text{ ,\quad for $|k| \le 1$,} \] -where -$k$ is \tcode{k} and +$\mathsf{\Pi}(\nu, k)$, +where $\mathsf{\Pi}$ is given by \eqref{sf.cmath.comp.ellint.3}, +$k$ is \tcode{k}, and $\nu$ is \tcode{nu}. +\begin{formula}{sf.cmath.comp.ellint.3} +\mathsf{\Pi}(\nu, k) = \mathsf{\Pi}(\nu, k, \pi / 2) \text{ ,\quad for $|k| \le 1$} +\end{formula} \pnum See also \ref{sf.cmath.ellint.3}. @@ -9726,7 +10204,7 @@ \indexlibraryglobal{cyl_bessel_if}% \indexlibraryglobal{cyl_bessel_il}% \indextext{Bessel functions!$\mathsf{I}_\nu$}% -\indextext{I nu@$\mathsf{I}_\nu$ (Bessell functions)}% +\indextext{I nu@$\mathsf{I}_\nu$ (Bessel functions)}% \begin{itemdecl} @\placeholder{floating-point-type}@ cyl_bessel_i(@\placeholder{floating-point-type}@ nu, @\placeholder{floating-point-type}@ x); float cyl_bessel_if(float nu, float x); @@ -9743,13 +10221,16 @@ \pnum \returns -\[ \mathsf{I}_\nu(x) = +$\mathsf{I}_\nu(x)$, +where $\mathsf{I}_\nu$ is given by \eqref{sf.cmath.cyl.bessel.i}, +$\nu$ is \tcode{nu}, and +$x$ is \tcode{x}. +\begin{formula}{sf.cmath.cyl.bessel.i} +\mathsf{I}_\nu(x) = \mathrm{i}^{-\nu} \mathsf{J}_\nu(\mathrm{i}x) = \sum_{k=0}^\infty \frac{(x/2)^{\nu+2k}}{k! \: \Gamma(\nu+k+1)} - \text{ ,\quad for $x \ge 0$,} \] -where -$\nu$ is \tcode{nu} and -$x$ is \tcode{x}. + \text{ ,\quad for $x \ge 0$} +\end{formula} \pnum \remarks @@ -9766,7 +10247,7 @@ \indexlibraryglobal{cyl_bessel_jf}% \indexlibraryglobal{cyl_bessel_jl}% \indextext{Bessel functions!$\mathsf{J}_\nu$}% -\indextext{J nu@$\mathsf{J}_\nu$ (Bessell functions)}% +\indextext{J nu@$\mathsf{J}_\nu$ (Bessel functions)}% \begin{itemdecl} @\placeholder{floating-point-type}@ cyl_bessel_j(@\placeholder{floating-point-type}@ nu, @\placeholder{floating-point-type}@ x); float cyl_bessel_jf(float nu, float x); @@ -9784,12 +10265,15 @@ \pnum \returns -\[ \mathsf{J}_\nu(x) = - \sum_{k=0}^\infty \frac{(-1)^k (x/2)^{\nu+2k}}{k! \: \Gamma(\nu+k+1)} - \text{ ,\quad for $x \ge 0$,} \] -where -$\nu$ is \tcode{nu} and +$\mathsf{J}_\nu(x)$, +where $\mathsf{J}_\nu$ is given by \eqref{sf.cmath.cyl.bessel.j}, +$\nu$ is \tcode{nu}, and $x$ is \tcode{x}. +\begin{formula}{sf.cmath.cyl.bessel.j} +\mathsf{J}_\nu(x) = + \sum_{k=0}^\infty \frac{(-1)^k (x/2)^{\nu+2k}}{k! \: \Gamma(\nu+k+1)} + \text{ ,\quad for $x \ge 0$} +\end{formula} \pnum \remarks @@ -9803,7 +10287,7 @@ \indexlibraryglobal{cyl_bessel_kf}% \indexlibraryglobal{cyl_bessel_kl}% \indextext{Bessel functions!$\mathsf{K}_\nu$}% -\indextext{K nu@$\mathsf{K}_\nu$ (Bessell functions)}% +\indextext{K nu@$\mathsf{K}_\nu$ (Bessel functions)}% \begin{itemdecl} @\placeholder{floating-point-type}@ cyl_bessel_k(@\placeholder{floating-point-type}@ nu, @\placeholder{floating-point-type}@ x); float cyl_bessel_kf(float nu, float x); @@ -9821,7 +10305,11 @@ \pnum \returns -\[% +$\mathsf{K}_\nu(x)$, +where $\mathsf{K}_\nu$ is given by \eqref{sf.cmath.cyl.bessel.k}, +$\nu$ is \tcode{nu}, and +$x$ is \tcode{x}. +\begin{formula}{sf.cmath.cyl.bessel.k} \mathsf{K}_\nu(x) = (\pi/2)\mathrm{i}^{\nu+1} ( \mathsf{J}_\nu(\mathrm{i}x) + \mathrm{i} \mathsf{N}_\nu(\mathrm{i}x) @@ -9843,10 +10331,7 @@ & \mbox{for $x \ge 0$ and integral $\nu$} \end{array} \right. -\] -where -$\nu$ is \tcode{nu} and -$x$ is \tcode{x}. +\end{formula} \pnum \remarks @@ -9882,7 +10367,11 @@ \pnum \returns -\[% +$\mathsf{N}_\nu(x)$, +where $\mathsf{N}_\nu$ is given by \eqref{sf.cmath.cyl.neumann}, +$\nu$ is \tcode{nu}, and +$x$ is \tcode{x}. +\begin{formula}{sf.cmath.cyl.neumann} \mathsf{N}_\nu(x) = \left\{ \begin{array}{cl} @@ -9898,10 +10387,7 @@ & \mbox{for $x \ge 0$ and integral $\nu$} \end{array} \right. -\] -where -$\nu$ is \tcode{nu} and -$x$ is \tcode{x}. +\end{formula} \pnum \remarks @@ -9935,12 +10421,15 @@ \pnum \returns -\[ \mathsf{F}(k, \phi) = - \int_0^\phi \! \frac{\mathsf{d}\theta}{\sqrt{1 - k^2 \sin^2 \theta}} - \text{ ,\quad for $|k| \le 1$,} \] -where -$k$ is \tcode{k} and +$\mathsf{F}(k, \phi)$, +where $\mathsf{F}$ is given by \eqref{sf.cmath.ellint.1}, +$k$ is \tcode{k}, and $\phi$ is \tcode{phi}. +\begin{formula}{sf.cmath.ellint.1} +\mathsf{F}(k, \phi) = + \int_0^\phi \! \frac{\mathsf{d}\theta}{\sqrt{1 - k^2 \sin^2 \theta}} + \text{ ,\quad for $|k| \le 1$} +\end{formula} \end{itemdescr} \rSec3[sf.cmath.ellint.2]{Incomplete elliptic integral of the second kind}% @@ -9965,11 +10454,14 @@ \pnum \returns -\[ \mathsf{E}(k, \phi) = \int_0^\phi \! \sqrt{1 - k^2 \sin^2 \theta} \, \mathsf{d}\theta - \text{ ,\quad for $|k| \le 1$,} \] -where -$k$ is \tcode{k} and +$\mathsf{E}(k, \phi)$, +where $\mathsf{E}$ is given by \eqref{sf.cmath.ellint.2}, +$k$ is \tcode{k}, and $\phi$ is \tcode{phi}. +\begin{formula}{sf.cmath.ellint.2} +\mathsf{E}(k, \phi) = \int_0^\phi \! \sqrt{1 - k^2 \sin^2 \theta} \, \mathsf{d}\theta + \text{ ,\quad for $|k| \le 1$} +\end{formula} \end{itemdescr} \rSec3[sf.cmath.ellint.3]{Incomplete elliptic integral of the third kind}% @@ -9996,12 +10488,15 @@ \pnum \returns -\[ \mathsf{\Pi}(\nu, k, \phi) = \int_0^\phi \! - \frac{ \mathsf{d}\theta }{ (1 - \nu \, \sin^2 \theta) \sqrt{1 - k^2 \sin^2 \theta} } \text{ ,\quad for $|k| \le 1$,} \] -where +$\mathsf{\Pi}(\nu, k, \phi)$, +where $\mathsf{\Pi}$ is given by \eqref{sf.cmath.ellint.3}, $\nu$ is \tcode{nu}, $k$ is \tcode{k}, and $\phi$ is \tcode{phi}. +\begin{formula}{sf.cmath.ellint.3} +\mathsf{\Pi}(\nu, k, \phi) = \int_0^\phi \! + \frac{ \mathsf{d}\theta }{ (1 - \nu \, \sin^2 \theta) \sqrt{1 - k^2 \sin^2 \theta} } \text{ ,\quad for $|k| \le 1$} +\end{formula} \end{itemdescr} \rSec3[sf.cmath.expint]{Exponential integral}% @@ -10026,15 +10521,14 @@ \pnum \returns -\[% +$\mathsf{Ei}(x)$, +where $\mathsf{Ei}$ is given by \eqref{sf.cmath.expint} and +$x$ is \tcode{x}. +\begin{formula}{sf.cmath.expint} \mathsf{Ei}(x) = - \int_{-x}^\infty \frac{e^{-t}} {t } \, \mathsf{d}t -\; -\] -where -$x$ is \tcode{x}. - +\end{formula} \end{itemdescr} \rSec3[sf.cmath.hermite]{Hermite polynomials}% @@ -10058,15 +10552,15 @@ \pnum \returns -\[% +$\mathsf{H}_n(x)$, +where $\mathsf{H}_n$ is given by \eqref{sf.cmath.hermite}, +$n$ is \tcode{n}, and +$x$ is \tcode{x}. +\begin{formula}{sf.cmath.hermite} \mathsf{H}_n(x) = (-1)^n e^{x^2} \frac{ \mathsf{d} ^n} { \mathsf{d}x^n} \, e^{-x^2} -\; -\] -where -$n$ is \tcode{n} and -$x$ is \tcode{x}. +\end{formula} \pnum \remarks @@ -10096,12 +10590,15 @@ \pnum \returns -\[ \mathsf{L}_n(x) = - \frac{e^x}{n!} \frac{\mathsf{d}^n}{\mathsf{d}x^n} \, (x^n e^{-x}) - \text{ ,\quad for $x \ge 0$,} \] -where -$n$ is \tcode{n} and +$\mathsf{L}_n(x)$, +where $\mathsf{L}_n$ is given by \eqref{sf.cmath.laguerre}, +$n$ is \tcode{n}, and $x$ is \tcode{x}. +\begin{formula}{sf.cmath.laguerre} +\mathsf{L}_n(x) = + \frac{e^x}{n!} \frac{\mathsf{d}^n}{\mathsf{d}x^n} \, (x^n e^{-x}) + \text{ ,\quad for $x \ge 0$} +\end{formula} \pnum \remarks @@ -10131,13 +10628,16 @@ \pnum \returns -\[ \mathsf{P}_\ell(x) = +$\mathsf{P}_\ell(x)$, +where $\mathsf{P}_\ell$ is given by \eqref{sf.cmath.legendre}, +$l$ is \tcode{l}, and +$x$ is \tcode{x}. +\begin{formula}{sf.cmath.legendre} +\mathsf{P}_\ell(x) = \frac{1}{2^\ell \, \ell!} \frac{\mathsf{d}^\ell}{\mathsf{d}x^\ell} \, (x^2 - 1) ^ \ell - \text{ ,\quad for $|x| \le 1$,} \] -where -$l$ is \tcode{l} and -$x$ is \tcode{x}. + \text{ ,\quad for $|x| \le 1$} +\end{formula} \pnum \remarks @@ -10167,7 +10667,10 @@ \pnum \returns -\[% +$\mathsf{\zeta}(x)$, +where $\mathsf{\zeta}$ is given by \eqref{sf.cmath.riemann.zeta} and +$x$ is \tcode{x}. +\begin{formula}{sf.cmath.riemann.zeta} \mathsf{\zeta}(x) = \left\{ \begin{array}{cl} @@ -10188,10 +10691,7 @@ & \mbox{for $x < 0$} \end{array} \right. -\; -\] -where -$x$ is \tcode{x}. +\end{formula} \end{itemdescr} \rSec3[sf.cmath.sph.bessel]{Spherical Bessel functions of the first kind}% @@ -10216,10 +10716,13 @@ \pnum \returns -\[ \mathsf{j}_n(x) = (\pi/2x)^{1\!/\!2} \mathsf{J}_{n + 1\!/\!2}(x) \text{ ,\quad for $x \ge 0$,} \] -where -$n$ is \tcode{n} and +$\mathsf{j}_n(x)$, +where $\mathsf{j}_n$ is given by \eqref{sf.cmath.sph.bessel}, +$n$ is \tcode{n}, and $x$ is \tcode{x}. +\begin{formula}{sf.cmath.sph.bessel} +\mathsf{j}_n(x) = (\pi/2x)^{1\!/\!2} \mathsf{J}_{n + 1\!/\!2}(x) \text{ ,\quad for $x \ge 0$} +\end{formula} \pnum \remarks @@ -10253,17 +10756,17 @@ \pnum \returns -\[ \mathsf{Y}_\ell^m(\theta, 0) \] -where -\[ \mathsf{Y}_\ell^m(\theta, \phi) = - (-1)^m \left[\frac{(2 \ell + 1)}{4 \pi} \frac{(\ell - m)!}{(\ell + m)!}\right]^{1/2} - \mathsf{P}_\ell^m (\cos\theta) e^{i m \phi} - \text{ ,\quad for $|m| \le \ell$,} -\] -and +$\mathsf{Y}_\ell^m(\theta, 0)$, +where $\mathsf{Y}_\ell^m$ is given by \eqref{sf.cmath.sph.legendre}, $l$ is \tcode{l}, $m$ is \tcode{m}, and $\theta$ is \tcode{theta}. +\begin{formula}{sf.cmath.sph.legendre} +\mathsf{Y}_\ell^m(\theta, \phi) = + (-1)^m \left[\frac{(2 \ell + 1)}{4 \pi} \frac{(\ell - m)!}{(\ell + m)!}\right]^{1/2} + \mathsf{P}_\ell^m (\cos\theta) e^{i m \phi} + \text{ ,\quad for $|m| \le \ell$} +\end{formula} \pnum \remarks @@ -10298,11 +10801,14 @@ \pnum \returns -\[ \mathsf{n}_n(x) = (\pi/2x)^{1\!/\!2} \mathsf{N}_{n + 1\!/\!2}(x) - \text{ ,\quad for $x \ge 0$,} \] -where -$n$ is \tcode{n} and +$\mathsf{n}_n(x)$, +where $\mathsf{n}_n$ is given by \eqref{sf.cmath.sph.neumann}, +$n$ is \tcode{n}, and $x$ is \tcode{x}. +\begin{formula}{sf.cmath.sph.neumann} +\mathsf{n}_n(x) = (\pi/2x)^{1\!/\!2} \mathsf{N}_{n + 1\!/\!2}(x) + \text{ ,\quad for $x \ge 0$} +\end{formula} \pnum \remarks @@ -10323,19 +10829,19 @@ \indexheader{numbers}% \begin{codeblock} namespace std::numbers { - template constexpr T e_v = @\unspec@; - template constexpr T log2e_v = @\unspec@; - template constexpr T log10e_v = @\unspec@; - template constexpr T pi_v = @\unspec@; - template constexpr T inv_pi_v = @\unspec@; - template constexpr T inv_sqrtpi_v = @\unspec@; - template constexpr T ln2_v = @\unspec@; - template constexpr T ln10_v = @\unspec@; - template constexpr T sqrt2_v = @\unspec@; - template constexpr T sqrt3_v = @\unspec@; - template constexpr T inv_sqrt3_v = @\unspec@; - template constexpr T egamma_v = @\unspec@; - template constexpr T phi_v = @\unspec@; + template constexpr T @\libglobal{e_v}@ = @\unspec@; + template constexpr T @\libglobal{log2e_v}@ = @\unspec@; + template constexpr T @\libglobal{log10e_v}@ = @\unspec@; + template constexpr T @\libglobal{pi_v}@ = @\unspec@; + template constexpr T @\libglobal{inv_pi_v}@ = @\unspec@; + template constexpr T @\libglobal{inv_sqrtpi_v}@ = @\unspec@; + template constexpr T @\libglobal{ln2_v}@ = @\unspec@; + template constexpr T @\libglobal{ln10_v}@ = @\unspec@; + template constexpr T @\libglobal{sqrt2_v}@ = @\unspec@; + template constexpr T @\libglobal{sqrt3_v}@ = @\unspec@; + template constexpr T @\libglobal{inv_sqrt3_v}@ = @\unspec@; + template constexpr T @\libglobal{egamma_v}@ = @\unspec@; + template constexpr T @\libglobal{phi_v}@ = @\unspec@; template<@\libconcept{floating_point}@ T> constexpr T e_v = @\seebelow@; template<@\libconcept{floating_point}@ T> constexpr T log2e_v = @\seebelow@; @@ -10351,19 +10857,19 @@ template<@\libconcept{floating_point}@ T> constexpr T egamma_v = @\seebelow@; template<@\libconcept{floating_point}@ T> 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; + inline constexpr double @\libglobal{e}@ = e_v; + inline constexpr double @\libglobal{log2e}@ = log2e_v; + inline constexpr double @\libglobal{log10e}@ = log10e_v; + inline constexpr double @\libglobal{pi}@ = pi_v; + inline constexpr double @\libglobal{inv_pi}@ = inv_pi_v; + inline constexpr double @\libglobal{inv_sqrtpi}@ = inv_sqrtpi_v; + inline constexpr double @\libglobal{ln2}@ = ln2_v; + inline constexpr double @\libglobal{ln10}@ = ln10_v; + inline constexpr double @\libglobal{sqrt2}@ = sqrt2_v; + inline constexpr double @\libglobal{sqrt3}@ = sqrt3_v; + inline constexpr double @\libglobal{inv_sqrt3}@ = inv_sqrt3_v; + inline constexpr double @\libglobal{egamma}@ = egamma_v; + inline constexpr double @\libglobal{phi}@ = phi_v; } \end{codeblock} @@ -10397,3 +10903,8691 @@ \pnum A program that instantiates a primary template of a mathematical constant variable template is ill-formed. + +\rSec1[linalg]{Basic linear algebra algorithms} + +\rSec2[linalg.overview]{Overview} + +\pnum +Subclause \ref{linalg} defines basic linear algebra algorithms. +The algorithms that access the elements of arrays +view those elements through \tcode{mdspan}\iref{views.multidim}. + +\rSec2[linalg.syn]{Header \tcode{} synopsis} + +\indexheader{linalg}% +\begin{codeblock} +namespace std::linalg { + // \ref{linalg.tags.order}, storage order tags + struct column_major_t; + inline constexpr column_major_t column_major; + struct row_major_t; + inline constexpr row_major_t row_major; + + // \ref{linalg.tags.triangle}, triangle tags + struct upper_triangle_t; + inline constexpr upper_triangle_t upper_triangle; + struct lower_triangle_t; + inline constexpr lower_triangle_t lower_triangle; + + // \ref{linalg.tags.diagonal}, diagonal tags + struct implicit_unit_diagonal_t; + inline constexpr implicit_unit_diagonal_t implicit_unit_diagonal; + struct explicit_diagonal_t; + inline constexpr explicit_diagonal_t explicit_diagonal; + + // \ref{linalg.layout.packed}, class template layout_blas_packed + template + class layout_blas_packed; + + // \ref{linalg.helpers}, exposition-only helpers + + // \ref{linalg.helpers.concepts}, linear algebra argument concepts + template + constexpr bool @\exposid{is-mdspan}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{in-vector}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{out-vector}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{inout-vector}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{in-matrix}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{out-matrix}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{inout-matrix}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{possibly-packed-inout-matrix}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{in-object}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{out-object}@ = @\seebelow@; // \expos + + template + concept @\exposconcept{inout-object}@ = @\seebelow@; // \expos + + // \ref{linalg.scaled}, scaled in-place transformation + + // \ref{linalg.scaled.scaledaccessor}, class template \tcode{scaled_accessor} + template + class scaled_accessor; + + // \ref{linalg.scaled.scaled}, function template \tcode{scaled} + template + constexpr auto scaled(ScalingFactor alpha, mdspan x); + + // \ref{linalg.conj}, conjugated in-place transformation + + // \ref{linalg.conj.conjugatedaccessor}, class template \tcode{conjugated_accessor} + template + class conjugated_accessor; + + // \ref{linalg.conj.conjugated}, function template \tcode{conjugated} + template + constexpr auto conjugated(mdspan a); + + // \ref{linalg.transp}, transpose in-place transformation + + // \ref{linalg.transp.layout.transpose}, class template \tcode{layout_transpose} + template + class layout_transpose; + + // \ref{linalg.transp.transposed}, function template \tcode{transposed} + template + constexpr auto transposed(mdspan a); + + // \ref{linalg.conjtransposed}, conjugated transpose in-place transformation + template + constexpr auto conjugate_transposed(mdspan a); + + // \ref{linalg.algs.blas1}, BLAS 1 algorithms + + // \ref{linalg.algs.blas1.givens}, Givens rotations + + // \ref{linalg.algs.blas1.givens.lartg}, compute Givens rotation + + template + struct setup_givens_rotation_result { + Real c; + Real s; + Real r; + }; + template + struct setup_givens_rotation_result> { + Real c; + complex s; + complex r; + }; + + template + setup_givens_rotation_result setup_givens_rotation(Real a, Real b) noexcept; + + template + setup_givens_rotation_result> + setup_givens_rotation(complex a, complex b) noexcept; + + // \ref{linalg.algs.blas1.givens.rot}, apply computed Givens rotation + template<@\exposconcept{inout-vector}@ InOutVec1, @\exposconcept{inout-vector}@ InOutVec2, class Real> + void apply_givens_rotation(InOutVec1 x, InOutVec2 y, Real c, Real s); + template + void apply_givens_rotation(ExecutionPolicy&& exec, + InOutVec1 x, InOutVec2 y, Real c, Real s); + template<@\exposconcept{inout-vector}@ InOutVec1, @\exposconcept{inout-vector}@ InOutVec2, class Real> + void apply_givens_rotation(InOutVec1 x, InOutVec2 y, Real c, complex s); + template + void apply_givens_rotation(ExecutionPolicy&& exec, + InOutVec1 x, InOutVec2 y, Real c, complex s); + + // \ref{linalg.algs.blas1.swap}, swap elements + template<@\exposconcept{inout-object}@ InOutObj1, @\exposconcept{inout-object}@ InOutObj2> + void swap_elements(InOutObj1 x, InOutObj2 y); + template + void swap_elements(ExecutionPolicy&& exec, + InOutObj1 x, InOutObj2 y); + + // \ref{linalg.algs.blas1.scal}, multiply elements by scalar + template + void scale(Scalar alpha, InOutObj x); + template + void scale(ExecutionPolicy&& exec, + Scalar alpha, InOutObj x); + + // \ref{linalg.algs.blas1.copy}, copy elements + template<@\exposconcept{in-object}@ InObj, @\exposconcept{out-object}@ OutObj> + void copy(InObj x, OutObj y); + template + void copy(ExecutionPolicy&& exec, + InObj x, OutObj y); + + // \ref{linalg.algs.blas1.add}, add elementwise + template<@\exposconcept{in-object}@ InObj1, @\exposconcept{in-object}@ InObj2, @\exposconcept{out-object}@ OutObj> + void add(InObj1 x, InObj2 y, OutObj z); + template + void add(ExecutionPolicy&& exec, + InObj1 x, InObj2 y, OutObj z); + + // \ref{linalg.algs.blas1.dot}, dot product of two vectors + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, class Scalar> + Scalar dot(InVec1 v1, InVec2 v2, Scalar init); + template + Scalar dot(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2, Scalar init); + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2> + auto dot(InVec1 v1, InVec2 v2); + template + auto dot(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2); + + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, class Scalar> + Scalar dotc(InVec1 v1, InVec2 v2, Scalar init); + template + Scalar dotc(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2, Scalar init); + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2> + auto dotc(InVec1 v1, InVec2 v2); + template + auto dotc(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2); + + // \ref{linalg.algs.blas1.ssq}, scaled sum of squares of a vector's elements + template + struct sum_of_squares_result { + Scalar scaling_factor; + Scalar scaled_sum_of_squares; + }; + template<@\exposconcept{in-vector}@ InVec, class Scalar> + sum_of_squares_result + vector_sum_of_squares(InVec v, sum_of_squares_result init); + template + sum_of_squares_result + vector_sum_of_squares(ExecutionPolicy&& exec, + InVec v, sum_of_squares_result init); + + // \ref{linalg.algs.blas1.nrm2}, Euclidean norm of a vector + template<@\exposconcept{in-vector}@ InVec, class Scalar> + Scalar vector_two_norm(InVec v, Scalar init); + template + Scalar vector_two_norm(ExecutionPolicy&& exec, InVec v, Scalar init); + template<@\exposconcept{in-vector}@ InVec> + auto vector_two_norm(InVec v); + template + auto vector_two_norm(ExecutionPolicy&& exec, InVec v); + + // \ref{linalg.algs.blas1.asum}, sum of absolute values of vector elements + template<@\exposconcept{in-vector}@ InVec, class Scalar> + Scalar vector_abs_sum(InVec v, Scalar init); + template + Scalar vector_abs_sum(ExecutionPolicy&& exec, InVec v, Scalar init); + template<@\exposconcept{in-vector}@ InVec> + auto vector_abs_sum(InVec v); + template + auto vector_abs_sum(ExecutionPolicy&& exec, InVec v); + + // \ref{linalg.algs.blas1.iamax}, index of maximum absolute value of vector elements + template<@\exposconcept{in-vector}@ InVec> + typename InVec::extents_type vector_idx_abs_max(InVec v); + template + typename InVec::extents_type vector_idx_abs_max(ExecutionPolicy&& exec, InVec v); + + // \ref{linalg.algs.blas1.matfrobnorm}, Frobenius norm of a matrix + template<@\exposconcept{in-matrix}@ InMat, class Scalar> + Scalar matrix_frob_norm(InMat A, Scalar init); + template + Scalar matrix_frob_norm(ExecutionPolicy&& exec, InMat A, Scalar init); + template<@\exposconcept{in-matrix}@ InMat> + auto matrix_frob_norm(InMat A); + template + auto matrix_frob_norm(ExecutionPolicy&& exec, InMat A); + + // \ref{linalg.algs.blas1.matonenorm}, one norm of a matrix + template<@\exposconcept{in-matrix}@ InMat, class Scalar> + Scalar matrix_one_norm(InMat A, Scalar init); + template + Scalar matrix_one_norm(ExecutionPolicy&& exec, InMat A, Scalar init); + template<@\exposconcept{in-matrix}@ InMat> + auto matrix_one_norm(InMat A); + template + auto matrix_one_norm(ExecutionPolicy&& exec, InMat A); + + // \ref{linalg.algs.blas1.matinfnorm}, infinity norm of a matrix + template<@\exposconcept{in-matrix}@ InMat, class Scalar> + Scalar matrix_inf_norm(InMat A, Scalar init); + template + Scalar matrix_inf_norm(ExecutionPolicy&& exec, InMat A, Scalar init); + template<@\exposconcept{in-matrix}@ InMat> + auto matrix_inf_norm(InMat A); + template + auto matrix_inf_norm(ExecutionPolicy&& exec, InMat A); + + // \ref{linalg.algs.blas2}, BLAS 2 algorithms + + // \ref{linalg.algs.blas2.gemv}, general matrix-vector product + template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void matrix_vector_product(InMat A, InVec x, OutVec y); + template + void matrix_vector_product(ExecutionPolicy&& exec, + InMat A, InVec x, OutVec y); + template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{out-vector}@ OutVec> + void matrix_vector_product(InMat A, InVec1 x, InVec2 y, OutVec z); + template + void matrix_vector_product(ExecutionPolicy&& exec, + InMat A, InVec1 x, InVec2 y, OutVec z); + + // \ref{linalg.algs.blas2.symv}, symmetric matrix-vector product + template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void symmetric_matrix_vector_product(InMat A, Triangle t, InVec x, OutVec y); + template + void symmetric_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec x, OutVec y); + template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, + @\exposconcept{out-vector}@ OutVec> + void symmetric_matrix_vector_product(InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); + template + void symmetric_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); + + // \ref{linalg.algs.blas2.hemv}, Hermitian matrix-vector product + template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void hermitian_matrix_vector_product(InMat A, Triangle t, InVec x, OutVec y); + template + void hermitian_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec x, OutVec y); + template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, + @\exposconcept{out-vector}@ OutVec> + void hermitian_matrix_vector_product(InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); + template + void hermitian_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); + + // \ref{linalg.algs.blas2.trmv}, triangular matrix-vector product + + // Overwriting triangular matrix-vector product + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{in-vector}@ InVec, + @\exposconcept{out-vector}@ OutVec> + void triangular_matrix_vector_product(InMat A, Triangle t, DiagonalStorage d, InVec x, + OutVec y); + template + void triangular_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InVec x, + OutVec y); + + // In-place triangular matrix-vector product + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-vector}@ InOutVec> + void triangular_matrix_vector_product(InMat A, Triangle t, DiagonalStorage d, InOutVec y); + template + void triangular_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutVec y); + + // Updating triangular matrix-vector product + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{out-vector}@ OutVec> + void triangular_matrix_vector_product(InMat A, Triangle t, DiagonalStorage d, + InVec1 x, InVec2 y, OutVec z); + template + void triangular_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InVec1 x, InVec2 y, OutVec z); + + // \ref{linalg.algs.blas2.trsv}, solve a triangular linear system + + // Solve a triangular linear system, not in place + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec, class BinaryDivideOp> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, + InVec b, OutVec x, BinaryDivideOp divide); + template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InVec b, OutVec x, BinaryDivideOp divide); + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, + InVec b, OutVec x); + template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InVec b, OutVec x); + + // Solve a triangular linear system, in place + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{inout-vector}@ InOutVec, class BinaryDivideOp> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, + InOutVec b, BinaryDivideOp divide); + template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutVec b, BinaryDivideOp divide); + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-vector}@ InOutVec> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, InOutVec b); + template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutVec b); + + // \ref{linalg.algs.blas2.rank1}, nonsymmetric rank-1 matrix update + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{inout-matrix}@ InOutMat> + void matrix_rank_1_update(InVec1 x, InVec2 y, InOutMat A); + template + void matrix_rank_1_update(ExecutionPolicy&& exec, + InVec1 x, InVec2 y, InOutMat A); + + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{inout-matrix}@ InOutMat> + void matrix_rank_1_update_c(InVec1 x, InVec2 y, InOutMat A); + template + void matrix_rank_1_update_c(ExecutionPolicy&& exec, + InVec1 x, InVec2 y, InOutMat A); + + // \ref{linalg.algs.blas2.symherrank1}, symmetric or Hermitian rank-1 matrix update + template + void symmetric_matrix_rank_1_update(Scalar alpha, InVec x, InOutMat A, Triangle t); + template + void symmetric_matrix_rank_1_update(ExecutionPolicy&& exec, + Scalar alpha, InVec x, InOutMat A, Triangle t); + template<@\exposconcept{in-vector}@ InVec, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_1_update(InVec x, InOutMat A, Triangle t); + template + void symmetric_matrix_rank_1_update(ExecutionPolicy&& exec, + InVec x, InOutMat A, Triangle t); + + template + void hermitian_matrix_rank_1_update(Scalar alpha, InVec x, InOutMat A, Triangle t); + template + void hermitian_matrix_rank_1_update(ExecutionPolicy&& exec, + Scalar alpha, InVec x, InOutMat A, Triangle t); + template<@\exposconcept{in-vector}@ InVec, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_1_update(InVec x, InOutMat A, Triangle t); + template + void hermitian_matrix_rank_1_update(ExecutionPolicy&& exec, + InVec x, InOutMat A, Triangle t); + + // \ref{linalg.algs.blas2.rank2}, symmetric and Hermitian rank-2 matrix updates + + // symmetric rank-2 matrix update + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_2_update(InVec1 x, InVec2 y, InOutMat A, Triangle t); + template + void symmetric_matrix_rank_2_update(ExecutionPolicy&& exec, + InVec1 x, InVec2 y, InOutMat A, Triangle t); + + // Hermitian rank-2 matrix update + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_2_update(InVec1 x, InVec2 y, InOutMat A, Triangle t); + template + void hermitian_matrix_rank_2_update(ExecutionPolicy&& exec, + InVec1 x, InVec2 y, InOutMat A, Triangle t); + + // \ref{linalg.algs.blas3}, BLAS 3 algorithms + + // \ref{linalg.algs.blas3.gemm}, general matrix-matrix product + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void matrix_product(InMat1 A, InMat2 B, OutMat C); + template + void matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, OutMat C); + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, @\exposconcept{out-matrix}@ OutMat> + void matrix_product(InMat1 A, InMat2 B, InMat3 E, OutMat C); + template + void matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, InMat3 E, OutMat C); + + // \ref{linalg.algs.blas3.xxmm}, symmetric, Hermitian, and triangular matrix-matrix product + + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, Triangle t, InMat2 B, OutMat C); + template + void symmetric_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, InMat2 B, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, Triangle t, InMat2 B, OutMat C); + template + void hermitian_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, InMat2 B, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, OutMat C); + template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, InMat2 B, Triangle t, OutMat C); + template + void symmetric_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, InMat2 B, Triangle t, OutMat C); + template + void hermitian_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, class DiagonalStorage, + @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, OutMat C); + template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); + template + void symmetric_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); + template + void hermitian_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, InMat3 E, + OutMat C); + template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, InMat3 E, + OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); + template + void symmetric_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); + template + void hermitian_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat3, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, InMat3 E, + OutMat C); + template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, InMat3 E, + OutMat C); + + // \ref{linalg.algs.blas3.trmm}, in-place triangular matrix-matrix product + + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_left_product(InMat A, Triangle t, DiagonalStorage d, InOutMat C); + template + void triangular_matrix_left_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutMat C); + + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_right_product(InMat A, Triangle t, DiagonalStorage d, InOutMat C); + template + void triangular_matrix_right_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutMat C); + + // \ref{linalg.algs.blas3.rankk}, rank-k update of a symmetric or Hermitian matrix + + // rank-k symmetric matrix update + template + void symmetric_matrix_rank_k_update(Scalar alpha, InMat A, InOutMat C, Triangle t); + template + void symmetric_matrix_rank_k_update(ExecutionPolicy&& exec, + Scalar alpha, InMat A, InOutMat C, Triangle t); + + template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_k_update(InMat A, InOutMat C, Triangle t); + template + void symmetric_matrix_rank_k_update(ExecutionPolicy&& exec, + InMat A, InOutMat C, Triangle t); + + // rank-k Hermitian matrix update + template + void hermitian_matrix_rank_k_update(Scalar alpha, InMat A, InOutMat C, Triangle t); + template + void hermitian_matrix_rank_k_update(ExecutionPolicy&& exec, + Scalar alpha, InMat A, InOutMat C, Triangle t); + + template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_k_update(InMat A, InOutMat C, Triangle t); + template + void hermitian_matrix_rank_k_update(ExecutionPolicy&& exec, + InMat A, InOutMat C, Triangle t); + + // \ref{linalg.algs.blas3.rank2k}, rank-2k update of a symmetric or Hermitian matrix + + // rank-2k symmetric matrix update + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_2k_update(InMat1 A, InMat2 B, InOutMat C, Triangle t); + template + void symmetric_matrix_rank_2k_update(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, InOutMat C, Triangle t); + + // rank-2k Hermitian matrix update + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_2k_update(InMat1 A, InMat2 B, InOutMat C, Triangle t); + template + void hermitian_matrix_rank_2k_update(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, InOutMat C, Triangle t); + + // \ref{linalg.algs.blas3.trsm}, solve multiple triangular linear systems + + // solve multiple triangular systems on the left, not-in-place + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat, class BinaryDivideOp> + void triangular_matrix_matrix_left_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); + template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_matrix_left_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); + template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); + + // solve multiple triangular systems on the right, not-in-place + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat, class BinaryDivideOp> + void triangular_matrix_matrix_right_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); + template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); + template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_matrix_right_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); + template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); + + // solve multiple triangular systems on the left, in-place + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{inout-matrix}@ InOutMat, class BinaryDivideOp> + void triangular_matrix_matrix_left_solve(InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); + template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_matrix_left_solve(InMat A, Triangle t, DiagonalStorage d, + InOutMat B); + template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B); + + // solve multiple triangular systems on the right, in-place + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{inout-matrix}@ InOutMat, class BinaryDivideOp> + void triangular_matrix_matrix_right_solve(InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); + template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_matrix_right_solve(InMat A, Triangle t, DiagonalStorage d, + InOutMat B); + template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B); +} +\end{codeblock} + +\rSec2[linalg.general]{General} + +\pnum +For the effects of all functions in \ref{linalg}, +when the effects are described as +``computes $R = E$'' or ``compute $R = E$'' +(for some $R$ and mathematical expression $E$), +the following apply: +\begin{itemize} +\item +$E$ has + the conventional mathematical meaning as written. +\item +The pattern $x^T$ should be read as + ``the transpose of $x$.'' +\item +The pattern $x^H$ should be read as + ``the conjugate transpose of $x$.'' +\item +When $R$ is the same name as a function parameter + whose type is a template parameter with \tcode{Out} in its name, + the intent is that the result of the computation + is written to the elements of the function parameter \tcode{R}. +\end{itemize} + +\pnum +Some of the functions and types in \ref{linalg} distinguish between +the ``rows'' and the ``columns'' of a matrix. +For a matrix \tcode{A} and a multidimensional index \tcode{i, j} in \tcode{A.extents()}, +\begin{itemize} +\item +\term{row} \tcode{i} of \tcode{A} is the set of elements \tcode{A[i, k1]} + for all \tcode{k1} such that \tcode{i, k1} is in \tcode{A.extents()}; and +\item +\term{column} \tcode{j} of \tcode{A} is the set of elements \tcode{A[k0, j]} + for all \tcode{k0} such that \tcode{k0, j} is in \tcode{A.extents()}. +\end{itemize} + +\pnum +Some of the functions in \ref{linalg} distinguish between +the ``upper triangle,'' ``lower triangle,'' and ``diagonal'' of a matrix. +\begin{itemize} +\item +The \defn{diagonal} is the set of all elements of \tcode{A} accessed by + \tcode{A[i,i]} for 0 $\le$ \tcode{i} < min(\tcode{A.extent(0)}, \tcode{A.extent(1)}). +\item +The \defnadj{upper}{triangle} of a matrix \tcode{A} is the set of all elements of + \tcode{A} accessed by \tcode{A[i,j]} with \tcode{i} $\le$ \tcode{j}. It includes the diagonal. +\item +The \defnadj{lower}{triangle} of \tcode{A} is the set of all elements of \tcode{A} + accessed by \tcode{A[i,j]} with \tcode{i} $\ge$ \tcode{j}. It includes the diagonal. +\end{itemize} + +\pnum +For any function \tcode{F} that takes +a parameter named \tcode{t}, +\tcode{t} applies to accesses done through the parameter preceding \tcode{t} in the parameter list of \tcode{F}. +Let \tcode{m} be such an access-modified function parameter. +\tcode{F} will only access the triangle of \tcode{m} specified by \tcode{t}. +For accesses \tcode{m[i, j]} outside the triangle specified by \tcode{t}, +\tcode{F} will use the value +\begin{itemize} +\item +\tcode{\exposid{conj-if-needed}(m[j, i])} if the name of \tcode{F} starts with \tcode{hermitian}, +\item +\tcode{m[j, i]} if the name of \tcode{F} starts with \tcode{symmetric}, or +\item +the additive identity if the name of \tcode{F} starts with \tcode{triangular}. +\end{itemize} +\begin{example} +Small vector product accessing only specified triangle. +It would not be a precondition violation for the non-accessed +matrix element to be non-zero. +\begin{codeblock} +template +void triangular_matrix_vector_2x2_product( + mdspan> m, + Triangle t, + mdspan> x, + mdspan> y) { + + static_assert(is_same_v || + is_same_v); + + if constexpr (is_same_v) { + y[0] = m[0,0] * x[0]; // \tcode{+ 0 * x[1]} + y[1] = m[1,0] * x[0] + m[1,1] * x[1]; + } else { // upper_triangle_t + y[0] = m[0,0] * x[0] + m[0,1] * x[1]; + y[1] = /* 0 * x[0] + */ m[1,1] * x[1]; + } +} +\end{codeblock} +\end{example} + +\pnum +For any function \tcode{F} that takes a parameter named \tcode{d}, +\tcode{d} applies to accesses done through +the previous-of-the-previous parameter of \tcode{d} +in the parameter list of \tcode{F}. +Let \tcode{m} be such an access-modified function parameter. +If \tcode{d} specifies that an implicit unit diagonal is to be assumed, then +\begin{itemize} +\item +\tcode{F} will not access the diagonal of \tcode{m}; and +\item +the algorithm will interpret \tcode{m} as if it has a unit diagonal, that is, +a diagonal each of whose elements behaves as a two-sided multiplicative identity +(even if \tcode{m}'s value type does not have +a two-sided multiplicative identity). +\end{itemize} +Otherwise, +if \tcode{d} specifies that an explicit diagonal is to be assumed, +then \tcode{F} will access the diagonal of \tcode{m}. + +\pnum +Within all the functions in \ref{linalg}, +any calls to \tcode{abs}, \tcode{conj}, \tcode{imag}, and \tcode{real} +are unqualified. + +\pnum +Two \tcode{mdspan} objects \tcode{x} and \tcode{y} \term{alias} each other, +if they have the same extents \tcode{e}, and +for every pack of integers \tcode{i} +which is a multidimensional index in \tcode{e}, +\tcode{x[i...]} and \tcode{y[i...]} refer to the same element. +\begin{note} +This means that +\tcode{x} and \tcode{y} view the same elements in the same order. +\end{note} + +\pnum +Two \tcode{mdspan} objects \tcode{x} and \tcode{y} \term{overlap} each other, +if for some pack of integers \tcode{i} +that is a multidimensional index in \tcode{x.extents()}, +there exists a pack of integers \tcode{j} +that is a multidimensional index in \tcode{y.extents()}, +such that \tcode{x[i...]} and \tcode{y[j...]} refer to the same element. +\begin{note} +Aliasing is a special case of overlapping. +If \tcode{x} and \tcode{y} do not overlap, +then they also do not alias each other. +\end{note} + +\rSec2[linalg.reqs]{Requirements} + +\rSec3[linalg.reqs.val]{Linear algebra value types} + +\pnum +Throughout \ref{linalg}, +the following types are +\defnadjx{linear algebra}{value types}{value type}: +\begin{itemize} +\item +the \tcode{value_type} type alias of +any input or output \tcode{mdspan} parameter(s) of +any function in \ref{linalg}; and +\item +the \tcode{Scalar} template parameter (if any) of +any function or class in \ref{linalg}. +\end{itemize} + +\pnum +Linear algebra value types shall model \libconcept{semiregular}. + +\pnum +A value-initialized object of linear algebra value type +shall act as the additive identity. + +\rSec3[linalg.reqs.alg]{Algorithm and class requirements} + +\pnum +\ref{linalg.reqs.alg} lists common requirements for +all algorithms and classes in \ref{linalg}. + +\pnum +All of the following statements presume +that the algorithm's asymptotic complexity requirements, if any, are satisfied. +\begin{itemize} +\item +The function may make arbitrarily many objects of any linear algebra value type, +value-initializing or direct-initializing them +with any existing object of that type. +\item +The \term{triangular solve algorithms} in +\ref{linalg.algs.blas2.trsv}, +\ref{linalg.algs.blas3.trmm}, +\ref{linalg.algs.blas3.trsm}, and +\ref{linalg.algs.blas3.inplacetrsm} +either have +a \tcode{BinaryDi\-videOp} template parameter (see \ref{linalg.algs.reqs}) and +a binary function object parameter \tcode{divide} of that type, +or they have effects equivalent to invoking such an algorithm. +Triangular solve algorithms interpret \tcode{divide(a, b)} as +\tcode{a} times the multiplicative inverse of \tcode{b}. +Each triangular solve algorithm uses a sequence of evaluations of +\tcode{*}, \tcode{*=}, \tcode{divide}, +unary \tcode{+}, binary \tcode{+}, \tcode{+=}, +unary \tcode{-}, binary \tcode{-}, \tcode{-=}, +and \tcode{=} operators +that would produce the result +specified by the algorithm's \Fundescx{Effects} and \Fundescx{Remarks} +when operating on elements of a field with noncommutative multiplication. +It is a precondition of the algorithm that +any addend, +any subtrahend, +any partial sum of addends in any order +(treating any difference as a sum with the second term negated), +any factor, +any partial product of factors respecting their order, +any numerator (first argument of \tcode{divide}), +any denominator (second argument of \tcode{divide}), +and any assignment +is a well-formed expression. +\item +Each function in +\ref{linalg.algs.blas1}, \ref{linalg.algs.blas2}, and \ref{linalg.algs.blas3} +that is not a triangular solve algorithm +will use a sequence of evaluations of +\tcode{*}, \tcode{*=}, \tcode{+}, \tcode{+=}, and \tcode{=} operators +that would produce the result +specified by the algorithm's \Fundescx{Effects} and \Fundescx{Remarks} +when operating on elements of a semiring with noncommutative multiplication. +It is a precondition of the algorithm that +any addend, +any partial sum of addends in any order, +any factor, +any partial product of factors respecting their order, +and any assignment +is a well-formed expression. +\item +If the function has an output \tcode{mdspan}, +then all addends, +subtrahends (for the triangular solve algorithms), +or results of the \tcode{divide} parameter on intermediate terms +(if the function takes a \tcode{divide} parameter) +are assignable and convertible to +the output \tcode{mdspan}'s \tcode{value_type}. +\item +The function may reorder addends and partial sums arbitrarily. +\begin{note} +Factors in each product are not reordered; +multiplication is not necessarily commutative. +\end{note} +\end{itemize} +\begin{note} +The above requirements do not prohibit +implementation approaches and optimization techniques +which are not user-observable. +In particular, if for all input and output arguments +the \tcode{value_type} is a floating-point type, +implementers are free to leverage approximations, +use arithmetic operations not explicitly listed above, and +compute floating point sums in any way that improves their accuracy. +\end{note} + +\pnum +\begin{note} +For all functions in \ref{linalg}, +suppose that all input and output \tcode{mdspan} have as \tcode{value_type} +a floating-point type, and +any \tcode{Scalar} template argument has a floating-point type. +Then, functions can do all of the following: +\begin{itemize} +\item +compute floating-point sums in any way +that improves their accuracy for arbitrary input; +\item +perform additional arithmetic operations +(other than those specified by the function's wording and \ref{linalg.reqs.alg}) +in order to improve performance or accuracy; and +\item +use approximations +(that might not be exact even if computing with real numbers), +instead of computations that would be exact +if it were possible to compute without rounding error; +\end{itemize} +as long as +\begin{itemize} +\item +the function satisfies the complexity requirements; and +\item +the function is logarithmically stable, +as defined in Demmel 2007\supercite{linalg-stable}. +Strassen's algorithm for matrix-matrix multiply +is an example of a logarithmically stable algorithm. +\end{itemize} +\end{note} + +\rSec2[linalg.tags]{Tag classes} + +\rSec3[linalg.tags.order]{Storage order tags} + +\pnum +The storage order tags describe +the order of elements in an \tcode{mdspan} with +\tcode{layout_blas_packed}\iref{linalg.layout.packed} layout. +\begin{itemdecl} +struct @\libglobal{column_major_t}@ { + explicit column_major_t() = default; +}; +inline constexpr column_major_t @\libglobal{column_major}@{}; + +struct @\libglobal{row_major_t}@ { + explicit row_major_t() = default; +}; +inline constexpr row_major_t @\libglobal{row_major}@{}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{column_major_t} indicates a column-major order, +and \tcode{row_major_t} indicates a row-major order. +\end{itemdescr} + +\rSec3[linalg.tags.triangle]{Triangle tags} + +\begin{itemdecl} +struct @\libglobal{upper_triangle_t}@ { + explicit upper_triangle_t() = default; +}; +inline constexpr upper_triangle_t @\libglobal{upper_triangle}@{}; + +struct @\libglobal{lower_triangle_t}@ { + explicit lower_triangle_t() = default; +}; +inline constexpr lower_triangle_t @\libglobal{lower_triangle}@{}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +These tag classes specify whether +algorithms and other users of a matrix (represented as an \tcode{mdspan}) +access the +upper triangle (\tcode{upper_triangle_t}) or +lower triangle (\tcode{lower_triangle_t}) +of the matrix (see also \ref{linalg.general}). +This is also subject to the restrictions of \tcode{implicit_unit_diagonal_t} +if that tag is also used as a function argument; see below. +\end{itemdescr} + +\rSec3[linalg.tags.diagonal]{Diagonal tags} + +\begin{itemdecl} +struct @\libglobal{implicit_unit_diagonal_t}@ { + explicit implicit_unit_diagonal_t() = default; +}; +inline constexpr implicit_unit_diagonal_t @\libglobal{implicit_unit_diagonal}@{}; + +struct @\libglobal{explicit_diagonal_t}@ { + explicit explicit_diagonal_t() = default; +}; +inline constexpr explicit_diagonal_t @\libglobal{explicit_diagonal}@{}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +These tag classes specify whether algorithms +access the matrix's diagonal entries, and if not, +then how algorithms interpret +the matrix's implicitly represented diagonal values. + +\pnum +The \tcode{implicit_unit_diagonal_t} tag indicates that +an implicit unit diagonal is to be assumed\iref{linalg.general}. + +\pnum +The \tcode{explicit_diagonal_t} tag indicates that +an explicit diagonal is used\iref{linalg.general}. +\end{itemdescr} + +\rSec2[linalg.layout.packed]{Layouts for packed matrix types} + +\rSec3[linalg.layout.packed.overview]{Overview} + +\pnum +\tcode{layout_blas_packed} is an \tcode{mdspan} layout mapping policy +that represents a square matrix that stores only the entries in one +triangle, in a packed contiguous format. +Its \tcode{Triangle} template parameter determines +whether an \tcode{mdspan} with this layout +stores the upper or lower triangle of the matrix. +Its \tcode{StorageOrder} template parameter determines +whether the layout packs the matrix's elements +in column-major or row-major order. + +\pnum +A \tcode{StorageOrder} of \tcode{column_major_t} +indicates column-major ordering. +This packs matrix elements +starting with the leftmost (least column index) column, and +proceeding column by column, from the top entry (least row index). + +\pnum +A \tcode{StorageOrder} of \tcode{row_major_t} +indicates row-major ordering. +This packs matrix elements +starting with the topmost (least row index) row, and +proceeding row by row, from the leftmost (least column index) entry. + +\pnum +\begin{note} +\tcode{layout_blas_packed} describes the data layout used by +the BLAS' +Symmetric Packed (SP), Hermitian Packed (HP), and Triangular Packed (TP) +matrix types. +\end{note} +\begin{codeblock} +namespace std::linalg { + template + class @\libglobal{layout_blas_packed}@ { + public: + using triangle_type = Triangle; + using storage_order_type = StorageOrder; + + template + struct mapping { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_blas_packed; + + // \ref{linalg.layout.packed.cons}, constructors + constexpr mapping() noexcept = default; + constexpr mapping(const mapping&) noexcept = default; + constexpr mapping(const extents_type&) noexcept; + template + constexpr explicit(!is_convertible_v) + mapping(const mapping& other) noexcept; + + constexpr mapping& operator=(const mapping&) noexcept = default; + + // \ref{linalg.layout.packed.obs}, observers + constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } + + constexpr index_type required_span_size() const noexcept; + + template + constexpr index_type operator() (Index0 ind0, Index1 ind1) const noexcept; + + static constexpr bool is_always_unique() noexcept { + return (extents_type::static_extent(0) != dynamic_extent && + extents_type::static_extent(0) < 2) || + (extents_type::static_extent(1) != dynamic_extent && + extents_type::static_extent(1) < 2); + } + static constexpr bool is_always_exhaustive() noexcept { return true; } + static constexpr bool is_always_strided() noexcept + { return is_always_unique(); } + + constexpr bool is_unique() const noexcept { + return @\exposid{extents_}@.extent(0) < 2; + } + constexpr bool is_exhaustive() const noexcept { return true; } + constexpr bool is_strided() const noexcept { + return @\exposid{extents_}@.extent(0) < 2; + } + + constexpr index_type stride(rank_type) const noexcept; + + template + friend constexpr bool operator==(const mapping&, const mapping&) noexcept; + + private: + extents_type @\exposid{extents_}@{}; // \expos + }; + }; +} +\end{codeblock} + +\begin{itemdescr} +\pnum +\mandates +\begin{itemize} +\item +\tcode{Triangle} is either \tcode{upper_triangle_t} or \tcode{lower_triangle_t}, +\item +\tcode{StorageOrder} is either \tcode{column_major_t} or \tcode{row_major_t}, +\item +\tcode{Extents} is a specialization of \tcode{std::extents}, +\item +\tcode{Extents::rank()} equals 2, +\item +one of +\begin{codeblock} +extents_type::static_extent(0) == dynamic_extent@\textrm{,}@ +extents_type::static_extent(1) == dynamic_extent@\textrm{, or}@ +extents_type::static_extent(0) == extents_type::static_extent(1) +\end{codeblock} +is \tcode{true}, and +\item +if \tcode{Extents::rank_dynamic() == 0} is \tcode{true}, +let $N_s$ be equal to \tcode{Extents::static_extent(0)}; then, +$N_s \times (N_s + 1)$ is representable as a value of type \tcode{index_type}. +\end{itemize} + +\pnum +\tcode{layout_blas_packed::mapping} is a trivially copyable type +that models \libconcept{regular} for each \tcode{T}, \tcode{SO}, and \tcode{E}. +\end{itemdescr} + +\rSec3[linalg.layout.packed.cons]{Constructors} + +\indexlibraryctor{layout_blas_packed::mapping}% +\begin{itemdecl} +constexpr mapping(const extents_type& e) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\begin{itemize} +\item +Let $N$ be equal to \tcode{e.extent(0)}. +Then, $N \times (N+1)$ is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. +\item +\tcode{e.extent(0)} equals \tcode{e.extent(1)}. +\end{itemize} + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{e}. +\end{itemdescr} + +\indexlibraryctor{layout_blas_packed::mapping}% +\begin{itemdecl} +template + explicit(!is_convertible_v) + constexpr mapping(const mapping& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\expects +Let $N$ be \tcode{other.extents().extent(0)}. +Then, $N \times (N+1)$ is representable as +a value of type \tcode{index_type}\iref{basic.fundamental}. + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +\end{itemdescr} + +\rSec3[linalg.layout.packed.obs]{Observers} + +\indexlibrarymember{layout_blas_packed::mapping}{required_span_size}% +\begin{itemdecl} +constexpr index_type required_span_size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{extents_}.extent(0) * (\exposid{extents_}.extent(0) + 1)/2}. +\begin{note} +For example, a 5 x 5 packed matrix +only stores 15 matrix elements. +\end{note} +\end{itemdescr} + +\indexlibrarymember{layout_blas_packed::mapping}{operator()}% +\begin{itemdecl} +template + constexpr index_type operator() (Index0 ind0, Index1 ind1) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}, +\item +\tcode{is_convertible_v} is \tcode{true}, +\item +\tcode{is_nothrow_constructible_v} is \tcode{true}, and +\item +\tcode{is_nothrow_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +Let \tcode{i} be \tcode{extents_type::\exposid{index-cast}(ind0)}, and +let \tcode{j} be \tcode{extents_type::\exposid{index-cast}(ind1)}. + +\pnum +\expects +\tcode{i, j} +is a multidimensional index in \exposid{extents_}\iref{mdspan.overview}. + +\pnum +\returns +Let \tcode{N} be \tcode{\exposid{extents_}.extent(0)}. +Then +\begin{itemize} +\item +\tcode{(*this)(j, i)} if \tcode{i > j} is \tcode{true}; otherwise +\item +\tcode{i + j * (j + 1)/2} if +\begin{codeblock} +is_same_v && is_same_v +\end{codeblock} +is \tcode{true} or +\begin{codeblock} +is_same_v && is_same_v +\end{codeblock} +is \tcode{true}; otherwise +\item +\tcode{j + N * i - i * (i + 1)/2}. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{layout_blas_packed::mapping}{stride}% +\begin{itemdecl} +constexpr index_type stride(rank_type r) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\begin{itemize} +\item +\tcode{is_strided()} is \tcode{true}, and +\item +\tcode{r < extents_type::rank()} is \tcode{true}. +\end{itemize} + +\pnum +\returns +\tcode{1}. +\end{itemdescr} + +\indexlibrarymember{layout_blas_packed::mapping}{operator==}% +\begin{itemdecl} +template + friend constexpr bool operator==(const mapping& x, const mapping& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.extents() == y.extents();} +\end{itemdescr} + +\rSec2[linalg.helpers]{Exposition-only helpers} + +\rSec3[linalg.helpers.abs]{\exposid{abs-if-needed}} + +\pnum +The name \exposid{abs-if-needed} denotes an exposition-only function object. +The expression \tcode{\exposid{abs-if-needed}(E)} for a subexpression \tcode{E} +whose type is \tcode{T} is expression-equivalent to: +\begin{itemize} +\item +\tcode{E} if \tcode{T} is an unsigned integer; +\item +otherwise, \tcode{std::abs(E)} if \tcode{T} is an arithmetic type, +\item +otherwise, \tcode{abs(E)}, +if that expression is valid, +with overload resolution performed in a context that includes the declaration +\begin{codeblock} +template U abs(U) = delete; +\end{codeblock} +If the function selected by overload resolution +does not return the absolute value of its input, +the program is ill-formed, no diagnostic required. +\end{itemize} + +\rSec3[linalg.helpers.conj]{\exposid{conj-if-needed}} + +\pnum +The name \exposid{conj-if-needed} denotes an exposition-only function object. +The expression \tcode{\exposid{conj-if-needed}(E)} for a subexpression \tcode{E} +whose type is \tcode{T} is expression-equivalent to: +\begin{itemize} +\item +\tcode{conj(E)}, +if \tcode{T} is not an arithmetic type and +the expression \tcode{conj(E)} is valid, +with overload resolution performed in a context that includes the declaration +\begin{codeblock} +template U conj(const U&) = delete; +\end{codeblock} +If the function selected by overload resolution +does not return the complex conjugate of its input, +the program is ill-formed, no diagnostic required; +\item +otherwise, \tcode{E}. +\end{itemize} + +\rSec3[linalg.helpers.real]{\exposid{real-if-needed}} + +\pnum +The name \exposid{real-if-needed} denotes an exposition-only function object. +The expression \tcode{\exposid{real-if-needed}(E)} for a subexpression \tcode{E} +whose type is \tcode{T} is expression-equivalent to: +\begin{itemize} +\item +\tcode{real(E)}, +if \tcode{T} is not an arithmetic type and +the expression \tcode{real(E)} is valid, +with overload resolution performed in a context that includes the declaration +\begin{codeblock} +template U real(const U&) = delete; +\end{codeblock} +If the function selected by overload resolution +does not return the real part of its input, +the program is ill-formed, no diagnostic required; +\item +otherwise, \tcode{E}. +\end{itemize} + +\rSec3[linalg.helpers.imag]{\exposid{imag-if-needed}} + +\pnum +The name \exposid{imag-if-needed} denotes an exposition-only function object. +The expression \tcode{\exposid{imag-if-needed}(E)} for a subexpression \tcode{E} +whose type is \tcode{T} is expression-equivalent to: +\begin{itemize} +\item +\tcode{imag(E)}, +if \tcode{T} is not an arithmetic type and the expression \tcode{imag(E)} +is valid, with overload resolution performed in a context +that includes the declaration +\begin{codeblock} +template U imag(const U&) = delete; +\end{codeblock} +If the function selected by overload resolution +does not return the imaginary part of its input, +the program is ill-formed, no diagnostic required; +\item +otherwise, \tcode{((void)E, T\{\})}. +\end{itemize} + +\rSec3[linalg.helpers.concepts]{Argument concepts} + +\pnum +The exposition-only concepts defined in this section +constrain the algorithms in \ref{linalg}. +\begin{codeblock} +template + constexpr bool @\exposid{is-mdspan}@ = false; + +template + constexpr bool @\exposid{is-mdspan}@> = true; + +template + concept @\defexposconcept{in-vector}@ = + @\exposid{is-mdspan}@ && T::rank() == 1; + +template + concept @\defexposconcept{out-vector}@ = + @\exposid{is-mdspan}@ && T::rank() == 1 && + is_assignable_v && T::is_always_unique(); + +template + concept @\defexposconcept{inout-vector}@ = + @\exposid{is-mdspan}@ && T::rank() == 1 && + is_assignable_v && T::is_always_unique(); + +template + concept @\defexposconcept{in-matrix}@ = + @\exposid{is-mdspan}@ && T::rank() == 2; + +template + concept @\defexposconcept{out-matrix}@ = + @\exposid{is-mdspan}@ && T::rank() == 2 && + is_assignable_v && T::is_always_unique(); + +template + concept @\defexposconcept{inout-matrix}@ = + @\exposid{is-mdspan}@ && T::rank() == 2 && + is_assignable_v && T::is_always_unique(); + +template + constexpr bool @\exposid{is-layout-blas-packed}@ = false; // \expos + +template + constexpr bool @\exposid{is-layout-blas-packed}@> = true; + +template + concept @\defexposconcept{possibly-packed-inout-matrix}@ = + @\exposid{is-mdspan}@ && T::rank() == 2 && + is_assignable_v && + (T::is_always_unique() || @\exposid{is-layout-blas-packed}@); + +template + concept @\defexposconcept{in-object}@ = + @\exposid{is-mdspan}@ && (T::rank() == 1 || T::rank() == 2); + +template + concept @\defexposconcept{out-object}@ = + @\exposid{is-mdspan}@ && (T::rank() == 1 || T::rank() == 2) && + is_assignable_v && T::is_always_unique(); + +template + concept @\defexposconcept{inout-object}@ = + @\exposid{is-mdspan}@ && (T::rank() == 1 || T::rank() == 2) && + is_assignable_v && T::is_always_unique(); +\end{codeblock} + +\pnum +If a function in \ref{linalg} accesses the elements +of a parameter constrained by +\exposconcept{in-vector}, +\exposconcept{in-matrix}, or +\exposconcept{in-object}, +those accesses will not modify the elements. + +\pnum +Unless explicitly permitted, any +\exposconcept{inout-vector}, +\exposconcept{inout-matrix}, +\exposconcept{inout-object}, +\exposconcept{out-vector}, +\exposconcept{out-matrix}, +\exposconcept{out-object}, or +\exposconcept{possibly-packed-inout-matrix} +parameter of a function in \ref{linalg} +shall not overlap any other \tcode{mdspan} parameter of the function. + +\rSec3[linalg.helpers.mandates]{Mandates} + +\pnum +\begin{note} +These exposition-only helper functions use +the less constraining input concepts even for the output arguments, +because the additional constraint for assignability of elements +is not necessary, and +they are sometimes used in a context +where the third argument is an input type too. +\end{note} + +\begin{codeblock} +template + requires(@\exposid{is-mdspan}@ && @\exposid{is-mdspan}@) + constexpr + bool @\exposid{compatible-static-extents}@(size_t r1, size_t r2) { // \expos + return MDS1::static_extent(r1) == dynamic_extent || + MDS2::static_extent(r2) == dynamic_extent || + MDS1::static_extent(r1) == MDS2::static_extent(r2); + } + +template<@\exposconcept{in-vector}@ In1, @\exposconcept{in-vector}@ In2, @\exposconcept{in-vector}@ Out> + constexpr bool @\exposid{possibly-addable}@() { // \expos + return @\exposid{compatible-static-extents}@(0, 0) && + @\exposid{compatible-static-extents}@(0, 0) && + @\exposid{compatible-static-extents}@(0, 0); + } + +template<@\exposconcept{in-matrix}@ In1, @\exposconcept{in-matrix}@ In2, @\exposconcept{in-matrix}@ Out> + constexpr bool @\exposid{possibly-addable}@() { // \expos + return @\exposid{compatible-static-extents}@(0, 0) && + @\exposid{compatible-static-extents}@(1, 1) && + @\exposid{compatible-static-extents}@(0, 0) && + @\exposid{compatible-static-extents}@(1, 1) && + @\exposid{compatible-static-extents}@(0, 0) && + @\exposid{compatible-static-extents}@(1, 1); + } + +template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{in-vector}@ InVec, @\exposconcept{in-vector}@ OutVec> + constexpr bool @\exposid{possibly-multipliable}@() { // \expos + return @\exposid{compatible-static-extents}@(0, 0) && + @\exposid{compatible-static-extents}@(1, 0); + } + +template<@\exposconcept{in-vector}@ InVec, @\exposconcept{in-matrix}@ InMat, @\exposconcept{in-vector}@ OutVec> + constexpr bool @\exposid{possibly-multipliable}@() { // \expos + return @\exposid{compatible-static-extents}@(0, 1) && + @\exposid{compatible-static-extents}@(0, 0); + } + +template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ OutMat> + constexpr bool @\exposid{possibly-multipliable}@() { // \expos + return @\exposid{compatible-static-extents}@(0, 0) && + @\exposid{compatible-static-extents}@(1, 1) && + @\exposid{compatible-static-extents}@(1, 0); + } +\end{codeblock} + +\rSec3[linalg.helpers.precond]{Preconditions} + +\pnum +\begin{note} +These exposition-only helper functions use +the less constraining input concepts even for the output arguments, +because the additional constraint for assignability of elements +is not necessary, and +they are sometimes used in a context +where the third argument is an input type too. +\end{note} + +\begin{codeblock} +constexpr bool @\exposid{addable}@( // \expos + const @\exposconcept{in-vector}@ auto& in1, const @\exposconcept{in-vector}@ auto& in2, const @\exposconcept{in-vector}@ auto& out) { + return out.extent(0) == in1.extent(0) && out.extent(0) == in2.extent(0); +} + +constexpr bool @\exposid{addable}@( // \expos + const @\exposconcept{in-matrix}@ auto& in1, const @\exposconcept{in-matrix}@ auto& in2, const @\exposconcept{in-matrix}@ auto& out) { + return out.extent(0) == in1.extent(0) && out.extent(1) == in1.extent(1) && + out.extent(0) == in2.extent(0) && out.extent(1) == in2.extent(1); +} + +constexpr bool @\exposid{multipliable}@( // \expos + const @\exposconcept{in-matrix}@ auto& in_mat, const @\exposconcept{in-vector}@ auto& in_vec, const @\exposconcept{in-vector}@ auto& out_vec) { + return out_vec.extent(0) == in_mat.extent(0) && in_mat.extent(1) == in_vec.extent(0); +} + +constexpr bool @\exposid{multipliable}@( // \expos + const @\exposconcept{in-vector}@ auto& in_vec, const @\exposconcept{in-matrix}@ auto& in_mat, const @\exposconcept{in-vector}@ auto& out_vec) { + return out_vec.extent(0) == in_mat.extent(1) && in_mat.extent(0) == in_vec.extent(0); +} + +constexpr bool @\exposid{multipliable}@( // \expos + const @\exposconcept{in-matrix}@ auto& in_mat1, const @\exposconcept{in-matrix}@ auto& in_mat2, const @\exposconcept{in-matrix}@ auto& out_mat) { + return out_mat.extent(0) == in_mat1.extent(0) && out_mat.extent(1) == in_mat2.extent(1) && + in_mat1.extent(1) == in_mat2.extent(0); +} +\end{codeblock} + +\rSec2[linalg.scaled]{Scaled in-place transformation} + +\rSec3[linalg.scaled.intro]{Introduction} + +\pnum +The \tcode{scaled} function +takes a value \tcode{alpha} and an \tcode{mdspan} \tcode{x}, and +returns a new read-only \tcode{mdspan} +that represents +the elementwise product of \tcode{alpha} with each element of \tcode{x}. +\begin{example} +\begin{codeblock} +using Vec = mdspan>; + +// z = alpha * x + y +void z_equals_alpha_times_x_plus_y(double alpha, Vec x, Vec y, Vec z) { + add(scaled(alpha, x), y, z); +} + +// z = alpha * x + beta * y +void z_equals_alpha_times_x_plus_beta_times_y(double alpha, Vec x, double beta, Vec y, Vec z) { + add(scaled(alpha, x), scaled(beta, y), z); +} +\end{codeblock} +\end{example} + +\rSec3[linalg.scaled.scaledaccessor]{Class template \tcode{scaled_accessor}} + +\pnum +The class template \tcode{scaled_accessor} is an \tcode{mdspan} accessor policy +which upon access produces scaled elements. +It is part of the implementation of \tcode{scaled}\iref{linalg.scaled.scaled}. +\begin{codeblock} +namespace std::linalg { + template + class @\libglobal{scaled_accessor}@ { + public: + using element_type = + add_const_t() * declval())>; + using reference = remove_const_t; + using data_handle_type = NestedAccessor::data_handle_type; + using offset_policy = scaled_accessor; + + constexpr scaled_accessor() = default; + template + explicit(!is_convertible_v) + constexpr scaled_accessor(const scaled_accessor& other); + constexpr scaled_accessor(const ScalingFactor& s, const NestedAccessor& a); + + constexpr reference access(data_handle_type p, size_t i) const; + constexpr offset_policy::data_handle_type offset(data_handle_type p, size_t i) const; + + constexpr const ScalingFactor& scaling_factor() const noexcept { return @\exposid{scaling-factor}@; } + constexpr const NestedAccessor& nested_accessor() const noexcept { return @\exposid{nested-accessor}@; } + + private: + ScalingFactor @\exposid{scaling-factor}@{}; // \expos + NestedAccessor @\exposid{nested-accessor}@{}; // \expos + }; +} +\end{codeblock} + +\pnum +\mandates +\begin{itemize} +\item +\tcode{element_type} is valid and denotes a type, +\item +\tcode{is_copy_constructible_v} is \tcode{true}, +\item +\tcode{is_reference_v} is \tcode{false}, +\item +\tcode{ScalingFactor} models \libconcept{semiregular}, and +\item +\tcode{NestedAccessor} meets the accessor policy requirements\iref{mdspan.accessor.reqmts}. +\end{itemize} + +\indexlibraryctor{scaled_accessor}% +\begin{itemdecl} +template + explicit(!is_convertible_v) + constexpr scaled_accessor(const scaled_accessor& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +\begin{itemize} +\item +Direct-non-list-initializes \exposid{scaling-factor} +with \tcode{other.scaling_factor()}, and +\item +direct-non-list-initializes \exposid{nested-accessor} +with \tcode{other.nested_accessor()}. +\end{itemize} +\end{itemdescr} + +\indexlibraryctor{scaled_accessor}% +\begin{itemdecl} +constexpr scaled_accessor(const ScalingFactor& s, const NestedAccessor& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +Direct-non-list-initializes \exposid{scaling-factor} with \tcode{s}, and +\item +direct-non-list-initializes \exposid{nested-accessor} with \tcode{a}. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{scaled_accessor}{access}% +\begin{itemdecl} +constexpr reference access(data_handle_type p, size_t i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{codeblock} +scaling_factor() * NestedAccessor::element_type(@\exposid{nested-accessor}@.access(p, i)) +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{scaled_accessor}{offset}% +\begin{itemdecl} +constexpr offset_policy::data_handle_type offset(data_handle_type p, size_t i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{nested-accessor}.offset(p, i)} +\end{itemdescr} + +\rSec3[linalg.scaled.scaled]{Function template \tcode{scaled}} + +\pnum +The \tcode{scaled} function template takes +a scaling factor \tcode{alpha} and +an \tcode{mdspan} \tcode{x}, and +returns a new read-only \tcode{mdspan} with the same domain as \tcode{x}, +that represents the elementwise product of \tcode{alpha} +with each element of \tcode{x}. + +\indexlibraryglobal{scaled}% +\begin{itemdecl} + template + constexpr auto scaled(ScalingFactor alpha, mdspan x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{SA} be \tcode{scaled_accessor}. + +\pnum +\returns +\begin{codeblock} +mdspan(x.data_handle(), x.mapping(), + SA(alpha, x.accessor())) +\end{codeblock} +\end{itemdescr} + +\pnum +\begin{example} +\begin{codeblock} +void test_scaled(mdspan> x) +{ + auto x_scaled = scaled(5.0, x); + for (int i = 0; i < x.extent(0); ++i) { + assert(x_scaled[i] == 5.0 * x[i]); + } +} +\end{codeblock} +\end{example} + +\rSec2[linalg.conj]{Conjugated in-place transformation} + +\rSec3[linalg.conj.intro]{Introduction} + +\pnum +The \tcode{conjugated} function takes an \tcode{mdspan} \tcode{x}, +and returns a new read-only \tcode{mdspan} \tcode{y} +with the same domain as \tcode{x}, +whose elements are the complex conjugates +of the corresponding elements of \tcode{x}. + +\rSec3[linalg.conj.conjugatedaccessor]{Class template \tcode{conjugated_accessor}} + +\pnum +The class template \tcode{conjugated_accessor} +is an \tcode{mdspan} accessor policy +which upon access produces conjugate elements. +It is part of the implementation of +\tcode{conjugated}\iref{linalg.conj.conjugated}. + +\begin{codeblock} +namespace std::linalg { + template + class @\libglobal{conjugated_accessor}@ { + public: + using element_type = + add_const_t()))>; + using reference = remove_const_t; + using data_handle_type = typename NestedAccessor::data_handle_type; + using offset_policy = conjugated_accessor; + + constexpr conjugated_accessor() = default; + template + explicit(!is_convertible_v>) + constexpr conjugated_accessor(const conjugated_accessor& other); + + constexpr reference access(data_handle_type p, size_t i) const; + + constexpr typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const; + + constexpr const Accessor& nested_accessor() const noexcept { return @\exposid{nested-accessor_}@; } + + private: + NestedAccessor @\exposid{nested-accessor_}@{}; // \expos + }; +} +\end{codeblock} + +\pnum +\mandates +\begin{itemize} +\item +\tcode{element_type} is valid and denotes a type, +\item +\tcode{is_copy_constructible_v} is \tcode{true}, +\item +\tcode{is_reference_v} is \tcode{false}, and +\item +\tcode{NestedAccessor} meets the accessor policy requirements\iref{mdspan.accessor.reqmts}. +\end{itemize} + +\indexlibraryctor{conjugated_accessor}% +\begin{itemdecl} +constexpr conjugated_accessor(const NestedAccessor& acc); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Direct-non-list-initializes +\exposid{nested-accessor_} with \tcode{acc}. +\end{itemdescr} + +\indexlibraryctor{conjugated_accessor}% +\begin{itemdecl} +template + explicit(!is_convertible_v>) + constexpr conjugated_accessor(const conjugated_accessor& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} +is \tcode{true}. + +\pnum +\effects +Direct-non-list-initializes \exposid{nested-accessor_} +with \tcode{other.nested_accessor()}. +\end{itemdescr} + +\indexlibrarymember{conjugated_accessor}{access}% +\begin{itemdecl} +constexpr reference access(data_handle_type p, size_t i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{conj-if-needed}(NestedAccessor::element_type(\exposid{nested-accessor_}.access(p, i)))} +\end{itemdescr} + +\indexlibrarymember{conjugated_accessor}{offset}% +\begin{itemdecl} +constexpr typename offset_policy::data_handle_type offset(data_handle_type p, size_t i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{nested-accessor_}.offset(p, i)} +\end{itemdescr} + +\rSec3[linalg.conj.conjugated]{Function template \tcode{conjugated}} + +\begin{itemdecl} + template + constexpr auto @\libglobal{conjugated}@(mdspan a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{A} be +\begin{itemize} +\item +\tcode{remove_cvref_t} +if \tcode{Accessor} is a specialization of \tcode{conjugated_accessor}; +\item +otherwise, +\tcode{Accessor} if \tcode{remove_cvref_t} is an arithmetic type; +\item +otherwise, +\tcode{conjugated_accessor} +if the expression \tcode{conj(E)} is valid for any subexpression \tcode{E} +whose type is \tcode{remove_cvref_t} +with overload resolution performed in a context that includes the declaration +\tcode{template U conj(const U\&) = delete;}; +\item +otherwise, +\tcode{Accessor}. +\end{itemize} + +\pnum +\returns +Let \tcode{MD} be \tcode{mdspan}. +\begin{itemize} +\item +\tcode{MD(a.data_handle(), a.mapping(), a.accessor().nested_accessor())} +if \tcode{Accessor} is a\newline specialization of \tcode{conjugated_accessor}; +\item +otherwise, +\tcode{a}, if \tcode{is_same_v} is \tcode{true}; +\item +otherwise, +\tcode{MD(a.data_handle(), a.mapping(), conjugated_accessor(a.accessor()))}. +\end{itemize} +\end{itemdescr} + +\pnum +\begin{example} +\begin{codeblock} +void test_conjugated_complex(mdspan, extents> a) { + auto a_conj = conjugated(a); + for (int i = 0; i < a.extent(0); ++i) { + assert(a_conj[i] == conj(a[i]); + } + auto a_conj_conj = conjugated(a_conj); + for (int i = 0; i < a.extent(0); ++i) { + assert(a_conj_conj[i] == a[i]); + } +} + +void test_conjugated_real(mdspan> a) { + auto a_conj = conjugated(a); + for (int i = 0; i < a.extent(0); ++i) { + assert(a_conj[i] == a[i]); + } + auto a_conj_conj = conjugated(a_conj); + for (int i = 0; i < a.extent(0); ++i) { + assert(a_conj_conj[i] == a[i]); + } +} +\end{codeblock} +\end{example} + +\rSec2[linalg.transp]{Transpose in-place transformation} + +\rSec3[linalg.transp.intro]{Introduction} + +\pnum +\tcode{layout_transpose} is an \tcode{mdspan} layout mapping policy +that swaps the two indices, extents, and strides +of any unique \tcode{mdspan} layout mapping policy. + +\pnum +The \tcode{transposed} function takes an \tcode{mdspan} +representing a matrix, and returns a new \tcode{mdspan} +representing the transpose of the input matrix. + +\rSec3[linalg.transp.helpers]{Exposition-only helpers for \tcode{layout_transpose} and \tcode{transposed}} + +\pnum +The exposition-only \exposid{transpose-extents} function +takes an \tcode{extents} object representing the extents of a matrix, +and returns a new \tcode{extents} object +representing the extents of the transpose of the matrix. + +\pnum +The exposition-only alias template +\tcode{\exposid{transpose-extents-t}} +gives the type of \tcode{\exposid{transpose-ex\-tents}(e)} +for a given \tcode{extents} object \tcode{e} of type \tcode{InputExtents}. +\begin{itemdecl} +template + constexpr extents + @\exposid{transpose-extents}@(const extents& in); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{extents(in.extent(1), in.extent(0))} +\end{itemdescr} + +\begin{codeblock} +template + using @\exposid{transpose-extents-t}@ = + decltype(@\exposid{transpose-extents}@(declval())); // \expos +\end{codeblock} + +\rSec3[linalg.transp.layout.transpose]{Class template \tcode{layout_transpose}} + +\pnum +\tcode{layout_transpose} is an \tcode{mdspan} layout mapping policy +that swaps the two indices, extents, and strides +of any \tcode{mdspan} layout mapping policy. + +\begin{codeblock} +namespace std::linalg { + template + class @\libglobal{layout_transpose}@ { + public: + using nested_layout_type = Layout; + + template + struct mapping { + private: + using @\exposid{nested-mapping-type}@ = + typename Layout::template mapping<@\exposid{transpose-extents-t}@>; // \expos + + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_transpose; + + constexpr explicit mapping(const @\exposid{nested-mapping-type}@&); + + constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } + + constexpr index_type required_span_size() const + { return @\exposid{nested-mapping_}@.required_span_size(); + + template + constexpr index_type operator()(Index0 ind0, Index1 ind1) const + { return @\exposid{nested-mapping_}@(ind1, ind0); } + + constexpr const @\exposid{nested-mapping-type}@& nested_mapping() const noexcept + { return @\exposid{nested-mapping_}@; } + + static constexpr bool is_always_unique() noexcept + { return @\exposid{nested-mapping-type}@::is_always_unique(); } + static constexpr bool is_always_exhaustive() noexcept + { return @\exposid{nested-mapping-type}@::is_always_exhaustive(); } + static constexpr bool is_always_strided() noexcept + { return @\exposid{nested-mapping-type}@::is_always_strided(); } + + constexpr bool is_unique() const { return @\exposid{nested-mapping_}@.is_unique(); } + constexpr bool is_exhaustive() const { return @\exposid{nested-mapping_}@.is_exhaustive(); } + constexpr bool is_strided() const { return @\exposid{nested-mapping_}@.is_strided(); } + + constexpr index_type stride(size_t r) const; + + template + friend constexpr bool operator==(const mapping& x, const mapping& y); + }; + + private: + @\exposid{nested-mapping-type}@ @\exposid{nested-mapping_}@; // \expos + extents_type @\exposid{extents_}@; // \expos + }; +} +\end{codeblock} + +\pnum +\tcode{Layout} shall meet +the layout mapping policy requirements\iref{mdspan.layout.policy.reqmts}. + +\pnum +\mandates +\begin{itemize} +\item +\tcode{Extents} is a specialization of \tcode{std::extents}, and +\item +\tcode{Extents::rank()} equals 2. +\end{itemize} + +\indexlibraryctor{layout_transpose::mapping}% +\begin{itemdecl} +constexpr explicit mapping(const @\exposid{nested-mapping-type}@& map); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +Initializes \exposid{nested-mapping_} with \tcode{map}, and +\item +initializes \exposid{extents_} +with \tcode{\exposid{transpose-extents}(map.extents())}. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{layout_transpose::mapping}{stride}% +\begin{itemdecl} +constexpr index_type stride(size_t r) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\begin{itemize} +\item +\tcode{is_strided()} is \tcode{true}, and +\item +\tcode{r < 2} is \tcode{true}. +\end{itemize} + +\pnum +\returns +\tcode{\exposid{nested-mapping_}.stride(r == 0 ? 1 : 0)} +\end{itemdescr} + +\indexlibrarymember{layout_transpose::mapping}{operator==}% +\begin{itemdecl} +template + friend constexpr bool operator==(const mapping& x, const mapping& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The expression +\tcode{x.\exposid{nested-mapping_} == y.\exposid{nested-mapping_}} +is well-formed and its result is convertible to \tcode{bool}. + +\pnum +\returns +\tcode{x.\exposid{nested-mapping_} == y.\exposid{nested-mapping_}}. +\end{itemdescr} + +\rSec3[linalg.transp.transposed]{Function template \tcode{transposed}} + +\pnum +The \tcode{transposed} function +takes a rank-2 \tcode{mdspan} representing a matrix, and +returns a new \tcode{mdspan} representing the input matrix's transpose. +The input matrix's data are not modified, and +the returned \tcode{mdspan} accesses the input matrix's data in place. +\indexlibraryglobal{transposed}% +\begin{itemdecl} + template + constexpr auto transposed(mdspan a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{Extents::rank() == 2} is \tcode{true}. + +\pnum +Let \tcode{ReturnExtents} be +\tcode{\exposid{transpose-extents-t}}. +Let \tcode{R} be +\tcode{mdspan}, +where \tcode{ReturnLayout} is: +\begin{itemize} +\item +\tcode{layout_right} if \tcode{Layout} is \tcode{layout_left}; +\item +otherwise, \tcode{layout_left} if \tcode{Layout} is \tcode{layout_right}; +\item +otherwise, \tcode{layout_right_padded} if \tcode{Layout} is\newline +\tcode{layout_left_padded} +for some \tcode{size_t} value \tcode{PaddingValue}; +\item +otherwise, \tcode{layout_left_padded} if \tcode{Layout} is\newline +\tcode{layout_right_padded} +for some \tcode{size_t} value \tcode{PaddingValue}; +\item +otherwise, \tcode{layout_stride} if \tcode{Layout} is \tcode{layout_stride}; +\item +otherwise, +\tcode{layout_blas_packed}, +if \tcode{Layout} is\newline +\tcode{layout_blas_packed} +for some \tcode{Triangle} and \tcode{StorageOrder}, where +\begin{itemize} +\item +\tcode{OppositeTriangle} is +\begin{codeblock} +conditional_t, + lower_triangle_t, upper_triangle_t> +\end{codeblock} +and +\item +\tcode{OppositeStorageOrder} is +\begin{codeblock} +conditional_t, row_major_t, column_major_t> +\end{codeblock} +\end{itemize} +\item +otherwise, \tcode{NestedLayout} +if \tcode{Layout} is \tcode{layout_transpose} +for some \tcode{NestedLay\-out}; +\item +otherwise, \tcode{layout_transpose}. +\end{itemize} + +\pnum +\returns +With \tcode{ReturnMapping} being +the type \tcode{typename ReturnLayout::template mapping}: +\begin{itemize} +\item +if \tcode{Layout} is \tcode{layout_left}, \tcode{layout_right}, or +a specialization of \tcode{layout_blas_packed}, +\begin{codeblock} +R(a.data_handle(), ReturnMapping(@\exposid{transpose-extents}@(a.mapping().extents())), + a.accessor()) +\end{codeblock} +\item +otherwise, +\begin{codeblock} +R(a.data_handle(), ReturnMapping(@\exposid{transpose-extents}@(a.mapping().extents()), + a.mapping().stride(1)), a.accessor()) +\end{codeblock} +if \tcode{Layout} is \tcode{layout_left_padded} +for some \tcode{size_t} value \tcode{PaddingValue}; +\item +otherwise, +\begin{codeblock} +R(a.data_handle(), ReturnMapping(@\exposid{transpose-extents}@(a.mapping().extents()), + a.mapping().stride(0)), a.accessor()) +\end{codeblock} +if \tcode{Layout} is \tcode{layout_right_padded} +for some \tcode{size_t} value \tcode{PaddingValue}; +\item +otherwise, if \tcode{Layout} is \tcode{layout_stride}, +\begin{codeblock} +R(a.data_handle(), ReturnMapping(@\exposid{transpose-extents}@(a.mapping().extents()), + array{a.mapping().stride(1), a.mapping().stride(0)}), a.accessor()) +\end{codeblock} +\item +otherwise, if \tcode{Layout} is a specialization of \tcode{layout_transpose}, +\begin{codeblock} +R(a.data_handle(), a.mapping().nested_mapping(), a.accessor()) +\end{codeblock} +\item +otherwise, +\begin{codeblock} +R(a.data_handle(), ReturnMapping(a.mapping()), a.accessor()) +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\pnum +\begin{example} +\begin{codeblock} +void test_transposed(mdspan> a) { + const auto num_rows = a.extent(0); + const auto num_cols = a.extent(1); + + auto a_t = transposed(a); + assert(num_rows == a_t.extent(1)); + assert(num_cols == a_t.extent(0)); + assert(a.stride(0) == a_t.stride(1)); + assert(a.stride(1) == a_t.stride(0)); + + for (size_t row = 0; row < num_rows; ++row) { + for (size_t col = 0; col < num_rows; ++col) { + assert(a[row, col] == a_t[col, row]); + } + } + + auto a_t_t = transposed(a_t); + assert(num_rows == a_t_t.extent(0)); + assert(num_cols == a_t_t.extent(1)); + assert(a.stride(0) == a_t_t.stride(0)); + assert(a.stride(1) == a_t_t.stride(1)); + + for (size_t row = 0; row < num_rows; ++row) { + for (size_t col = 0; col < num_rows; ++col) { + assert(a[row, col] == a_t_t[row, col]); + } + } +} +\end{codeblock} +\end{example} + +\rSec2[linalg.conjtransposed]{Conjugate transpose in-place transform} + +\pnum +The \tcode{conjugate_transposed} function +returns a conjugate transpose view of an object. +This combines the effects of \tcode{transposed} and \tcode{conjugated}. +\indexlibraryglobal{conjugate_transposed}% +\begin{itemdecl} + template + constexpr auto conjugate_transposed(mdspan a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return conjugated(transposed(a));} +\end{itemdescr} + +\pnum +\begin{example} +\begin{codeblock} +void test_conjugate_transposed(mdspan, extents> a) { + const auto num_rows = a.extent(0); + const auto num_cols = a.extent(1); + + auto a_ct = conjugate_transposed(a); + assert(num_rows == a_ct.extent(1)); + assert(num_cols == a_ct.extent(0)); + assert(a.stride(0) == a_ct.stride(1)); + assert(a.stride(1) == a_ct.stride(0)); + + for (size_t row = 0; row < num_rows; ++row) { + for (size_t col = 0; col < num_rows; ++col) { + assert(a[row, col] == conj(a_ct[col, row])); + } + } + + auto a_ct_ct = conjugate_transposed(a_ct); + assert(num_rows == a_ct_ct.extent(0)); + assert(num_cols == a_ct_ct.extent(1)); + assert(a.stride(0) == a_ct_ct.stride(0)); + assert(a.stride(1) == a_ct_ct.stride(1)); + + for (size_t row = 0; row < num_rows; ++row) { + for (size_t col = 0; col < num_rows; ++col) { + assert(a[row, col] == a_ct_ct[row, col]); + assert(conj(a_ct[col, row]) == a_ct_ct[row, col]); + } + } +} +\end{codeblock} +\end{example} + +\rSec2[linalg.algs.reqs]{Algorithm requirements based on template parameter name} + +\pnum +Throughout +\ref{linalg.algs.blas1}, \ref{linalg.algs.blas2}, and \ref{linalg.algs.blas3}, +where the template parameters are not constrained, +the names of template parameters are used to express the following constraints. +\begin{itemize} +\item +\tcode{is_execution_policy::value} +is \tcode{true}\iref{execpol.type}. +\item +\tcode{Real} is any type such that \tcode{complex} is +specified\iref{complex.numbers.general}. +\item +\tcode{Triangle} is either \tcode{upper_triangle_t} or \tcode{lower_triangle_t}. +\item +\tcode{DiagonalStorage} is +either \tcode{implicit_unit_diagonal_t} or \tcode{explicit_diagonal_t}. +\end{itemize} +\begin{note} +Function templates that have a template parameter named \tcode{ExecutionPolicy} +are parallel algorithms\iref{algorithms.parallel.defns}. +\end{note} + +\rSec2[linalg.algs.blas1]{BLAS 1 algorithms} + +\rSec3[linalg.algs.blas1.complexity]{Complexity} + +\pnum +\complexity +All algorithms in \ref{linalg.algs.blas1} with \tcode{mdspan} parameters +perform a count of \tcode{mdspan} array accesses +and arithmetic operations that is linear in +the maximum product of extents of any \tcode{mdspan} parameter. + +\rSec3[linalg.algs.blas1.givens]{Givens rotations} + +\rSec4[linalg.algs.blas1.givens.lartg]{Compute Givens rotation} + +\indexlibraryglobal{setup_givens_rotation}% +\begin{itemdecl} +template + setup_givens_rotation_result setup_givens_rotation(Real a, Real b) noexcept; + +template + setup_givens_rotation_result> + setup_givens_rotation(complex a, complex b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions compute the Givens plane rotation +represented by the two values $c$ and $s$ +such that the 2 x 2 system of equations +\begin{equation*} +\left[ \begin{matrix} +c & s \\ +-\overline{s} & c \\ +\end{matrix} \right] +\cdot +\left[ \begin{matrix} +a \\ +b \\ +\end{matrix} \right] += +\left[ \begin{matrix} +r \\ +0 \\ +\end{matrix} \right] +\end{equation*} + +holds, where $c$ is always a real scalar, and $c^2 + |s|^2 = 1$. +That is, $c$ and $s$ represent a 2 x 2 matrix, +that when multiplied by the right by the input vector +whose components are $a$ and $b$, +produces a result vector +whose first component $r$ is the Euclidean norm of the input vector, and +whose second component is zero. +\begin{note} +These functions correspond to the LAPACK function \tcode{xLARTG}\supercite{lapack}. +\end{note} + +\pnum +\returns +\tcode{{c, s, r}}, +where \tcode{c} and \tcode{s} form the Givens plane rotation +corresponding to the input \tcode{a} and \tcode{b}, +and \tcode{r} is the Euclidean norm of the two-component vector +formed by \tcode{a} and \tcode{b}. +\end{itemdescr} + +\rSec4[linalg.algs.blas1.givens.rot]{Apply a computed Givens rotation to vectors} + +\indexlibraryglobal{apply_givens_rotation}% +\begin{itemdecl} +template<@\exposconcept{inout-vector}@ InOutVec1, @\exposconcept{inout-vector}@ InOutVec2, class Real> + void apply_givens_rotation(InOutVec1 x, InOutVec2 y, Real c, Real s); +template + void apply_givens_rotation(ExecutionPolicy&& exec, + InOutVec1 x, InOutVec2 y, Real c, Real s); +template<@\exposconcept{inout-vector}@ InOutVec1, @\exposconcept{inout-vector}@ InOutVec2, class Real> + void apply_givens_rotation(InOutVec1 x, InOutVec2 y, Real c, complex s); +template + void apply_givens_rotation(ExecutionPolicy&& exec, + InOutVec1 x, InOutVec2 y, Real c, complex s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xROT}\supercite{blas1}. +\end{note} + +\pnum +\mandates +\tcode{\exposid{compatible-static-extents}(0, 0)} is \tcode{true}. + +\pnum +\expects +\tcode{x.extent(0)} equals \tcode{y.extent(0)}. + +\pnum +\effects +Applies the plane rotation +specified by \tcode{c} and \tcode{s} to +the input vectors \tcode{x} and \tcode{y}, +as if the rotation were a 2 x 2 matrix and +the input vectors were successive rows of a matrix with two rows. +\end{itemdescr} + +\rSec3[linalg.algs.blas1.swap]{Swap matrix or vector elements} + +\indexlibraryglobal{swap_elements}% +\begin{itemdecl} +template<@\exposconcept{inout-object}@ InOutObj1, @\exposconcept{inout-object}@ InOutObj2> + void swap_elements(InOutObj1 x, InOutObj2 y); +template + void swap_elements(ExecutionPolicy&& exec, InOutObj1 x, InOutObj2 y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xSWAP}\supercite{blas1}. +\end{note} + +\pnum +\constraints +\tcode{x.rank()} equals \tcode{y.rank()}. + +\pnum +\mandates +For all \tcode{r} in the range $[0, \tcode{x.rank()})$, +\begin{codeblock} +@\exposid{compatible-static-extents}@(r, r) +\end{codeblock} +is \tcode{true}. + +\pnum +\expects +\tcode{x.extents()} equals \tcode{y.extents()}. + +\pnum +\effects +Swaps all corresponding elements of \tcode{x} and \tcode{y}. +\end{itemdescr} + +\rSec3[linalg.algs.blas1.scal]{Multiply the elements of an object in place by a scalar} + +\indexlibraryglobal{scale}% +\begin{itemdecl} +template + void scale(Scalar alpha, InOutObj x); +template + void scale(ExecutionPolicy&& exec, Scalar alpha, InOutObj x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xSCAL}\supercite{blas1}. +\end{note} + +\pnum +\effects +Overwrites $x$ with the result of +computing the elementwise multiplication $\alpha x$, +where the scalar $\alpha$ is \tcode{alpha}. +\end{itemdescr} + +\rSec3[linalg.algs.blas1.copy]{Copy elements of one matrix or vector into another} + +\indexlibraryglobal{copy}% +\begin{itemdecl} +template<@\exposconcept{in-object}@ InObj, @\exposconcept{out-object}@ OutObj> + void copy(InObj x, OutObj y); +template + void copy(ExecutionPolicy&& exec, InObj x, OutObj y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xCOPY\supercite{blas1}}. +\end{note} + +\pnum +\constraints +\tcode{x.rank()} equals \tcode{y.rank()}. + +\pnum +\mandates +For all \tcode{r} in the range $[ 0, \tcode{x.rank()})$, +\begin{codeblock} +@\exposid{compatible-static-extents}@(r, r) +\end{codeblock} +is \tcode{true}. + +\pnum +\expects +\tcode{x.extents()} equals \tcode{y.extents()}. + +\pnum +\effects +Assigns each element of $x$ to the corresponding element of $y$. +\end{itemdescr} + +\rSec3[linalg.algs.blas1.add]{Add vectors or matrices elementwise} + +\indexlibraryglobal{add}% +\begin{itemdecl} +template<@\exposconcept{in-object}@ InObj1, @\exposconcept{in-object}@ InObj2, @\exposconcept{out-object}@ OutObj> + void add(InObj1 x, InObj2 y, OutObj z); +template + void add(ExecutionPolicy&& exec, + InObj1 x, InObj2 y, OutObj z); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xAXPY}\supercite{blas1}. +\end{note} + +\pnum +\constraints +\tcode{x.rank()}, \tcode{y.rank()}, and \tcode{z.rank()} are all equal. + +\pnum +\mandates +\tcode{\exposid{possibly-addable}()} is \tcode{true}. + +\pnum +\expects +\tcode{\exposid{addable}(x,y,z)} is \tcode{true}. + +\pnum +\effects +Computes $z = x + y$. + +\pnum +\remarks +\tcode{z} may alias \tcode{x} or \tcode{y}. +\end{itemdescr} + +\rSec3[linalg.algs.blas1.dot]{Dot product of two vectors} + +\pnum +\begin{note} +The functions in this section correspond to the BLAS +functions \tcode{xDOT}, \tcode{xDOTU}, and \tcode{xDOTC}\supercite{blas1}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas1.dot}. + +\pnum +\mandates +\tcode{\exposid{compatible-static-extents}(0, 0)} is \tcode{true}. + +\pnum +\expects +\tcode{v1.extent(0)} equals \tcode{v2.extent(0)}. + +\indexlibraryglobal{dot}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, class Scalar> + Scalar dot(InVec1 v1, InVec2 v2, Scalar init); +template + Scalar dot(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2, Scalar init); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions compute a non-conjugated dot product +with an explicitly specified result type. + +\pnum +\returns +Let \tcode{N} be \tcode{v1.extent(0)}. +\begin{itemize} +\item +\tcode{init} if \tcode{N} is zero; +\item +otherwise, +\tcode{\placeholdernc{GENERALIZED_SUM}(plus<>(), init, v1[0]*v2[0], \ldots, v1[N-1]*v2[N-1])}. +\end{itemize} + +\pnum +\remarks +If \tcode{InVec1::value_type}, \tcode{InVec2::value_type}, and \tcode{Scalar} +are all floating-point types or specializations of \tcode{complex}, +and if \tcode{Scalar} has higher precision +than \tcode{InVec1::value_type} or \tcode{InVec2::value_type}, +then intermediate terms in the sum use \tcode{Scalar}'s precision or greater. +\end{itemdescr} + +\indexlibraryglobal{dot}% +\begin{itemdecl} + template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2> + auto dot(InVec1 v1, InVec2 v2); + template + auto dot(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions compute a non-conjugated dot product with a default result type. + +\pnum +\effects +Let \tcode{T} be +\tcode{decltype(declval() * declval())}. +Then, +\begin{itemize} +\item +the two-parameter overload is equivalent to: +\begin{codeblock} +return dot(v1, v2, T{}); +\end{codeblock} +and +\item +the three-parameter overload is equivalent to: +\begin{codeblock} +return dot(std::forward(exec), v1, v2, T{}); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{dotc}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, class Scalar> + Scalar dotc(InVec1 v1, InVec2 v2, Scalar init); +template + Scalar dotc(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2, Scalar init); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +These functions compute a conjugated dot product +with an explicitly specified result type. + +\pnum +\effects +\begin{itemize} +\item +The three-parameter overload is equivalent to: +\begin{codeblock} +return dot(conjugated(v1), v2, init); +\end{codeblock} +and +\item +the four-parameter overload is equivalent to: +\begin{codeblock} +return dot(std::forward(exec), conjugated(v1), v2, init); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{dotc}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2> + auto dotc(InVec1 v1, InVec2 v2); +template + auto dotc(ExecutionPolicy&& exec, + InVec1 v1, InVec2 v2); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +These functions compute a conjugated dot product with a default result type. + +\pnum +\effects +Let \tcode{T} be \tcode{decltype(\exposid{conj-if-needed}(declval()) * decl\-val())}. +Then, +\begin{itemize} +\item +the two-parameter overload is equivalent to: +\begin{codeblock} +return dotc(v1, v2, T{}); +\end{codeblock} +and +\item +the three-parameter overload is equivalent to +\begin{codeblock} +return dotc(std::forward(exec), v1, v2, T{}); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec3[linalg.algs.blas1.ssq]{Scaled sum of squares of a vector's elements} + +\indexlibraryglobal{vector_sum_of_squares}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec, class Scalar> + sum_of_squares_result vector_sum_of_squares(InVec v, sum_of_squares_result init); +template + sum_of_squares_result vector_sum_of_squares(ExecutionPolicy&& exec, + InVec v, sum_of_squares_result init); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the LAPACK function \tcode{xLASSQ}\supercite{lapack}. +\end{note} + +\pnum +\mandates +\tcode{decltype(\exposid{abs-if-needed}(declval()))} is convertible to \tcode{Scalar}. + +\pnum +\effects +Returns a value \tcode{result} such that +\begin{itemize} +\item +\tcode{result.scaling_factor} is the maximum of \tcode{init.scaling_factor} and +\tcode{\exposid{abs-if-needed}(x[i])} +for all \tcode{i} in the domain of \tcode{v}; and +\item +let \tcode{s2init} be +\begin{codeblock} +init.scaling_factor * init.scaling_factor * init.scaled_sum_of_squares +\end{codeblock} +then \tcode{result.scaling_factor * result.scaling_factor * result.scaled_sum_of_squares} +equals the sum of \tcode{s2init} and +the squares of \tcode{\exposid{abs-if-needed}(x[i])} +for all \tcode{i} in the domain of \tcode{v}. +\end{itemize} + +\pnum +\remarks +If \tcode{InVec::value_type}, and \tcode{Scalar} +are all floating-point types or specializations of \tcode{complex}, +and if \tcode{Scalar} has higher precision +than \tcode{InVec::value_type}, +then intermediate terms in the sum use \tcode{Scalar}'s precision or greater. +\end{itemdescr} + +\rSec3[linalg.algs.blas1.nrm2]{Euclidean norm of a vector} + +\indexlibraryglobal{vector_two_norm}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec, class Scalar> + Scalar vector_two_norm(InVec v, Scalar init); +template + Scalar vector_two_norm(ExecutionPolicy&& exec, InVec v, Scalar init); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xNRM2}\supercite{blas1}. +\end{note} + +\pnum +\mandates +Let \tcode{a} be +\tcode{\exposid{abs-if-needed}(declval())}. +Then, \tcode{decltype(\linebreak init + a * a} is convertible to \tcode{Scalar}. + +\pnum +\returns +The square root of the sum of the square of \tcode{init} and the squares of the absolute values of the elements of \tcode{v}. +\begin{note} +For \tcode{init} equal to zero, this is the Euclidean norm +(also called 2-norm) of the vector \tcode{v}. +\end{note} + +\pnum +\remarks +If \tcode{InVec::value_type}, and \tcode{Scalar} +are all floating-point types or specializations of \tcode{complex}, +and if \tcode{Scalar} has higher precision +than \tcode{InVec::value_type}, +then intermediate terms in the sum use \tcode{Scalar}'s precision or greater. +\begin{note} +An implementation of this function for floating-point types \tcode{T} +can use the \tcode{scaled_sum_of_squares} result from +\tcode{vector_sum_of_squares(x, \{.scaling_factor=1.0, .scaled_sum_of_squares=init\})}. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{vector_two_norm}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec> + auto vector_two_norm(InVec v); +template + auto vector_two_norm(ExecutionPolicy&& exec, InVec v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Let \tcode{a} be +\tcode{\exposid{abs-if-needed}(declval())}. +Let \tcode{T} be \tcode{decltype(a * a)}. +Then, +\begin{itemize} +\item +the one-parameter overload is equivalent to: +\begin{codeblock} +return vector_two_norm(v, T{}); +\end{codeblock} +and +\item +the two-parameter overload is equivalent to: +\begin{codeblock} +return vector_two_norm(std::forward(exec), v, T{}); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec3[linalg.algs.blas1.asum]{Sum of absolute values of vector elements} + +\indexlibraryglobal{vector_abs_sum}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec, class Scalar> + Scalar vector_abs_sum(InVec v, Scalar init); +template + Scalar vector_abs_sum(ExecutionPolicy&& exec, InVec v, Scalar init); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{SASUM}, \tcode{DASUM}, \tcode{SCASUM}, and \tcode{DZASUM}\supercite{blas1}. +\end{note} + +\pnum +\mandates +\begin{codeblock} +decltype(init + @\exposid{abs-if-needed}@(@\exposid{real-if-needed}@(declval())) + + @\exposid{abs-if-needed}@(@\exposid{imag-if-needed}@(declval()))) +\end{codeblock} +is convertible to \tcode{Scalar}. + +\pnum +\returns +Let \tcode{N} be \tcode{v.extent(0)}. +\begin{itemize} +\item +\tcode{init} if \tcode{N} is zero; +\item +otherwise, if \tcode{InVec::value_type} is an arithmetic type, +\begin{codeblock} +@\placeholdernc{GENERALIZED_SUM}@(plus<>(), init, @\exposid{abs-if-needed}@(v[0]), @\ldots@, @\exposid{abs-if-needed}@(v[N-1])) +\end{codeblock} +\item +otherwise, +\begin{codeblock} +@\placeholdernc{GENERALIZED_SUM}@(plus<>(), init, + @\exposid{abs-if-needed}@(@\exposid{real-if-needed}@(v[0])) + @\exposid{abs-if-needed}@(@\exposid{imag-if-needed}@(v[0])), + @\ldots@, + @\exposid{abs-if-needed}@(@\exposid{real-if-needed}@(v[N-1])) + @\exposid{abs-if-needed}@(@\exposid{imag-if-needed}@(v[N-1]))) +\end{codeblock} +\end{itemize} + +\pnum +\remarks +If \tcode{InVec::value_type} and \tcode{Scalar} +are all floating-point types or specializations of \tcode{complex}, +and if \tcode{Scalar} has higher precision +than \tcode{InVec::value_type}, +then intermediate terms in the sum use \tcode{Scalar}'s precision or greater. +\end{itemdescr} + +\indexlibraryglobal{vector_abs_sum}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec> + auto vector_abs_sum(InVec v); +template + auto vector_abs_sum(ExecutionPolicy&& exec, InVec v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Let \tcode{T} be \tcode{typename InVec::value_type}. +Then, +\begin{itemize} +\item +the one-parameter overload is equivalent to: +\begin{codeblock} +return vector_abs_sum(v, T{}); +\end{codeblock} +and +\item +the two-parameter overload is equivalent to: +\begin{codeblock} +return vector_abs_sum(std::forward(exec), v, T{}); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec3[linalg.algs.blas1.iamax]{Index of maximum absolute value of vector elements} + +\indexlibraryglobal{vector_idx_abs_max}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec> + typename InVec::extents_type vector_idx_abs_max(InVec v); +template + typename InVec::extents_type vector_idx_abs_max(ExecutionPolicy&& exec, InVec v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{IxAMAX}\supercite{blas1}. +\end{note} + +\pnum +Let \tcode{T} be +\begin{codeblock} +decltype(@\exposid{abs-if-needed}@(@\exposid{real-if-needed}@(declval())) + + @\exposid{abs-if-needed}@(@\exposid{imag-if-needed}@(declval()))) +\end{codeblock} + +\pnum +\mandates +\tcode{declval() < declval()} is a valid expression. + +\pnum +\returns +\begin{itemize} +\item +\tcode{numeric_limits::max()} + if \tcode{v} has zero elements; +\item +otherwise, the index of the first element of \tcode{v} +having largest absolute value, +if \tcode{InVec::value_type} is an arithmetic type; +\item +otherwise, the index of the first element $\tcode{v}_e$ of \tcode{v} +for which +\begin{codeblock} +@\exposid{abs-if-needed}@(@\exposid{real-if-needed}@(@$\tcode{v}_e$@)) + @\exposid{abs-if-needed}@(@\exposid{imag-if-needed}@(@$\tcode{v}_e$@)) +\end{codeblock} +has the largest value. +\end{itemize} +\end{itemdescr} + +\rSec3[linalg.algs.blas1.matfrobnorm]{Frobenius norm of a matrix} + +\pnum +\begin{note} +These functions exist in the BLAS standard\supercite{blas-std} +but are not part of the reference implementation. +\end{note} + +\indexlibraryglobal{matrix_frob_norm}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Scalar> + Scalar matrix_frob_norm(InMat A, Scalar init); +template + Scalar matrix_frob_norm(ExecutionPolicy&& exec, InMat A, Scalar init); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +\mandates +Let \tcode{a} be +\tcode{\exposid{abs-if-needed}(declval())}. +Then, \tcode{decltype(\linebreak init + a * a)} +is convertible to \tcode{Scalar}. + +\pnum +\returns +The square root of the sum of squares +of \tcode{init} and the absolute values of the elements of \tcode{A}. +\begin{note} +For \tcode{init} equal to zero, +this is the Frobenius norm of the matrix \tcode{A}. +\end{note} + +\pnum +\remarks +If \tcode{InMat::value_type} and \tcode{Scalar} +are all floating-point types or specializations of \tcode{complex}, +and if \tcode{Scalar} has higher precision +than \tcode{InMat::value_type}, +then intermediate terms in the sum use \tcode{Scalar}'s precision or greater. +\end{itemdescr} + +\indexlibraryglobal{matrix_frob_norm}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat> + auto matrix_frob_norm(InMat A); +template + auto matrix_frob_norm(ExecutionPolicy&& exec, InMat A); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Let \tcode{a} be +\tcode{\exposid{abs-if-needed}(declval())}. +Let \tcode{T} be +\tcode{decltype(a * a)}. +Then, +\begin{itemize} +\item +the one-parameter overload is equivalent to: +\begin{codeblock} +return matrix_frob_norm(A, T{}); +\end{codeblock} +and +\item +the two-parameter overload is equivalent to: +\begin{codeblock} +return matrix_frob_norm(std::forward(exec), A, T{}); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec3[linalg.algs.blas1.matonenorm]{One norm of a matrix} + +\pnum +\begin{note} +These functions exist in the BLAS standard\supercite{blas-std} +but are not part of the reference implementation. +\end{note} + +\indexlibraryglobal{matrix_one_norm}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Scalar> + Scalar matrix_one_norm(InMat A, Scalar init); +template + Scalar matrix_one_norm(ExecutionPolicy&& exec, InMat A, Scalar init); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{decltype(\exposid{abs-if-needed}(declval()))} +is convertible to \tcode{Scalar}. + +\pnum +\returns +\begin{itemize} +\item +\tcode{init} if \tcode{A.extent(1)} is zero; +\item +otherwise, the sum of \tcode{init} and the one norm of the matrix $A$. +\end{itemize} +\begin{note} +The one norm of the matrix \tcode{A} +is the maximum over all columns of \tcode{A}, +of the sum of the absolute values of the elements of the column. +\end{note} + +\pnum +\remarks +If \tcode{InMat::value_type} and \tcode{Scalar} +are all floating-point types or specializations of \tcode{complex}, +and if \tcode{Scalar} has higher precision +than \tcode{InMat::value_type}, +then intermediate terms in the sum use \tcode{Scalar}'s precision or greater. +\end{itemdescr} + +\indexlibraryglobal{matrix_one_norm}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat> + auto matrix_one_norm(InMat A); +template + auto matrix_one_norm(ExecutionPolicy&& exec, InMat A); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Let \tcode{T} be +\tcode{decltype(\exposid{abs-if-needed}(declval())}. +Then, +\begin{itemize} +\item +the one-parameter overload is equivalent to: +\begin{codeblock} +return matrix_one_norm(A, T{}); +\end{codeblock} +and +\item +the two-parameter overload is equivalent to: +\begin{codeblock} +return matrix_one_norm(std::forward(exec), A, T{}); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec3[linalg.algs.blas1.matinfnorm]{Infinity norm of a matrix} + +\pnum +\begin{note} +These functions exist in the BLAS standard\supercite{blas-std} +but are not part of the reference implementation. +\end{note} + +\indexlibraryglobal{matrix_inf_norm}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Scalar> + Scalar matrix_inf_norm(InMat A, Scalar init); +template + Scalar matrix_inf_norm(ExecutionPolicy&& exec, InMat A, Scalar init); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{decltype(\exposid{abs-if-needed}(declval()))} +is convertible to \tcode{Scalar}. + +\pnum +\returns +\begin{itemize} +\item +\tcode{init} if \tcode{A.extent(0)} is zero; +\item +otherwise, +the sum of \tcode{init} and the infinity norm of the matrix \tcode{A}. +\end{itemize} +\begin{note} +The infinity norm of the matrix \tcode{A} +is the maximum over all rows of \tcode{A}, +of the sum of the absolute values +of the elements of the row. +\end{note} + +\pnum +\remarks +If \tcode{InMat::value_type} and \tcode{Scalar} +are all floating-point types or specializations of \tcode{complex}, +and if \tcode{Scalar} has higher precision +than \tcode{InMat::value_type}, +then intermediate terms in the sum use \tcode{Scalar}'s precision or greater. +\end{itemdescr} + +\indexlibraryglobal{matrix_inf_norm}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat> + auto matrix_inf_norm(InMat A); +template + auto matrix_inf_norm(ExecutionPolicy&& exec, InMat A); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +\effects +Let \tcode{T} be +\tcode{decltype(\exposid{abs-if-needed}(declval())}. +Then, +\begin{itemize} +\item +the one-parameter overload is equivalent to: +\begin{codeblock} +return matrix_inf_norm(A, T{}); +\end{codeblock} +and +\item +the two-parameter overload is equivalent to: +\begin{codeblock} +return matrix_inf_norm(std::forward(exec), A, T{}); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec2[linalg.algs.blas2]{BLAS 2 algorithms} + +\rSec3[linalg.algs.blas2.gemv]{General matrix-vector product} + +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xGEMV}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas2.gemv}. + +\pnum +\mandates +\begin{itemize} +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}, and +\item +\tcode{\exposid{possibly-addable}()} +is \tcode{true} for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(A,x,y)} is \tcode{true}, and +\item +\tcode{\exposid{addable}(x,y,z)} is \tcode{true} for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{A.extent(1)}}. + +\indexlibraryglobal{matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void matrix_vector_product(InMat A, InVec x, OutVec y); +template + void matrix_vector_product(ExecutionPolicy&& exec, InMat A, InVec x, OutVec y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform an overwriting matrix-vector product. + +\pnum +\effects +Computes $y = A x$. +\end{itemdescr} + +\begin{example} +\begin{codeblock} +constexpr size_t num_rows = 5; +constexpr size_t num_cols = 6; + +// y = 3.0 * A * x +void scaled_matvec_1(mdspan> A, + mdspan> x, mdspan> y) { + matrix_vector_product(scaled(3.0, A), x, y); +} + +// z = 7.0 times the transpose of A, times y +void scaled_transposed_matvec(mdspan> A, + mdspan> y, mdspan> z) { + matrix_vector_product(scaled(7.0, transposed(A)), y, z); +} +\end{codeblock} +\end{example} + +\indexlibraryglobal{matrix_vector_product}% +\begin{itemdecl} + template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{out-vector}@ OutVec> + void matrix_vector_product(InMat A, InVec1 x, InVec2 y, OutVec z); + template + void matrix_vector_product(ExecutionPolicy&& exec, + InMat A, InVec1 x, InVec2 y, OutVec z); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform an updating matrix-vector product. + +\pnum +\effects +Computes $z = y + A x$. + +\pnum +\remarks +\tcode{z} may alias \tcode{y}. +\end{itemdescr} + +\begin{example} +\begin{codeblock} +// y = 3.0 * A * x + 2.0 * y +void scaled_matvec_2(mdspan> A, + mdspan> x, mdspan> y) { + matrix_vector_product(scaled(3.0, A), x, scaled(2.0, y), y); +} +\end{codeblock} +\end{example} + +\rSec3[linalg.algs.blas2.symv]{Symmetric matrix-vector product} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xSYMV} and \tcode{xSPMV}\supercite{blas2}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas2.symv}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}; +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}; and +\item +\tcode{\exposid{possibly-addable}()} +is \tcode{true} for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}, +\item +\tcode{\exposid{multipliable}(A,x,y)} is \tcode{true}, and +\item +\tcode{\exposid{addable}(x,y,z)} is \tcode{true} +for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{A.extent(1)}}. + +\indexlibraryglobal{symmetric_matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void symmetric_matrix_vector_product(InMat A, Triangle t, InVec x, OutVec y); +template + void symmetric_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec x, OutVec y); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +These functions perform an overwriting symmetric matrix-vector product, +taking into account the \tcode{Triangle} parameter +that applies to the symmetric matrix \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $y = A x$. +\end{itemdescr} + +\indexlibraryglobal{symmetric_matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{out-vector}@ OutVec> + void symmetric_matrix_vector_product(InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); +template + void symmetric_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform an updating symmetric matrix-vector product, +taking into account the \tcode{Triangle} parameter +that applies to the symmetric matrix \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $z = y + A x$. + +\pnum +\remarks +\tcode{z} may alias \tcode{y}. +\end{itemdescr} + +\rSec3[linalg.algs.blas2.hemv]{Hermitian matrix-vector product} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xHEMV} and \tcode{xHPMV}\supercite{blas2}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas2.hemv}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument +has the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}; +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}; and +\item +\tcode{\exposid{possibly-addable}()} +is \tcode{true} for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}, +\item +\tcode{\exposid{multipliable}(A, x, y)} is \tcode{true}, and +\item +\tcode{\exposid{addable}(x, y, z)} is \tcode{true} for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{A.extent(1)}}. + +\indexlibraryglobal{hermitian_matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void hermitian_matrix_vector_product(InMat A, Triangle t, InVec x, OutVec y); +template + void hermitian_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec x, OutVec y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform an overwriting Hermitian matrix-vector product, +taking into account the \tcode{Triangle} parameter +that applies to the Hermitian matrix \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $y = A x$. +\end{itemdescr} + +\indexlibraryglobal{hermitian_matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{out-vector}@ OutVec> + void hermitian_matrix_vector_product(InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); +template + void hermitian_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, InVec1 x, InVec2 y, OutVec z); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform an updating Hermitian matrix-vector product, +taking into account the \tcode{Triangle} parameter +that applies to the Hermitian matrix \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $z = y + A x$. + +\pnum +\remarks +\tcode{z} may alias \tcode{y}. +\end{itemdescr} + +\rSec3[linalg.algs.blas2.trmv]{Triangular matrix-vector product} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xTRMV} and \tcode{xTPMV}\supercite{blas2}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas2.trmv}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}; +\item +\tcode{\exposid{compatible-static-extents}(0, 0)} +is \tcode{true}; +\item +\tcode{\exposid{compatible-static-extents}(0, 0)} +is \tcode{true} for those overloads that take an \tcode{x} parameter; and +\item +\tcode{\exposid{compatible-static-extents}(0, 0)} +is \tcode{true} for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}, +\item +\tcode{A.extent(0)} equals \tcode{y.extent(0)}, +\item +\tcode{A.extent(0)} equals \tcode{x.extent(0)} for those overloads that take an \tcode{x} parameter, and +\item +\tcode{A.extent(0)} equals \tcode{z.extent(0)} for those overloads that take a \tcode{z} parameter. +\end{itemize} + +\indexlibraryglobal{triangular_matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{in-vector}@ InVec, + @\exposconcept{out-vector}@ OutVec> + void triangular_matrix_vector_product(InMat A, Triangle t, DiagonalStorage d, InVec x, OutVec y); +template + void triangular_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InVec x, OutVec y); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +These functions perform +an overwriting triangular matrix-vector product, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $y = A x$. + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{A.extent(1)}}. +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-vector}@ InOutVec> + void triangular_matrix_vector_product(InMat A, Triangle t, DiagonalStorage d, InOutVec y); +template + void triangular_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutVec y); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +These functions perform an in-place triangular matrix-vector product, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. +\begin{note} +Performing this operation in place hinders parallelization. +However, other \tcode{ExecutionPolicy} specific optimizations, +such as vectorization, are still possible. +\end{note} + +\pnum +\effects +Computes a vector $y'$ such that $y' = A y$, +and assigns each element of $y'$ to the corresponding element of $y$. + +\pnum +\complexity +\bigoh{\tcode{y.extent(0)} \times \tcode{A.extent(1)}}. +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_vector_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{out-vector}@ OutVec> + void triangular_matrix_vector_product(InMat A, Triangle t, DiagonalStorage d, + InVec1 x, InVec2 y, OutVec z); +template + void triangular_matrix_vector_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InVec1 x, InVec2 y, OutVec z); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform an updating triangular matrix-vector product, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $z = y + A x$. + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{A.extent(1)}}. + +\pnum +\remarks +\tcode{z} may alias \tcode{y}. +\end{itemdescr} + +\rSec3[linalg.algs.blas2.trsv]{Solve a triangular linear system} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xTRSV} and \tcode{xTPSV}\supercite{blas2}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas2.trsv}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}; +\item +\tcode{\exposid{compatible-static-extents}(0, 0)} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 0)} +is \tcode{true} for those overloads that take an \tcode{x} parameter. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}, +\item +\tcode{A.extent(0)} equals \tcode{b.extent(0)}, and +\item +\tcode{A.extent(0)} equals \tcode{x.extent(0)} +for those overloads that take an \tcode{x} parameter. +\end{itemize} + +\indexlibraryglobal{triangular_matrix_vector_solve}% +\begin{itemdecl} + template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec, class BinaryDivideOp> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, + InVec b, OutVec x, BinaryDivideOp divide); + template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InVec b, OutVec x, BinaryDivideOp divide); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +These functions perform +a triangular solve, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes a vector $x'$ such that $b = A x'$, +and assigns each element of $x'$ to the corresponding element of $x$. +If no such $x'$ exists, +then the elements of \tcode{x} are valid but unspecified. + +\pnum +\complexity +\bigoh{\tcode{A.extent(1)} \times \tcode{b.extent(0)}}. +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_vector_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{in-vector}@ InVec, @\exposconcept{out-vector}@ OutVec> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, InVec b, OutVec x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_vector_solve(A, t, d, b, x, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_vector_solve}% +\begin{itemdecl} +template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InVec b, OutVec x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_vector_solve(std::forward(exec), + A, t, d, b, x, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_vector_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{inout-vector}@ InOutVec, class BinaryDivideOp> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, + InOutVec b, BinaryDivideOp divide); +template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutVec b, BinaryDivideOp divide); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform an in-place triangular solve, +taking into account the \tcode{Triangle} and \tcode{Diagonal\-Storage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. +\begin{note} +Performing triangular solve in place hinders parallelization. +However, other \tcode{ExecutionPolicy} specific optimizations, +such as vectorization, are still possible. +\end{note} + +\pnum +\effects +Computes a vector $x'$ such that $b = A x'$, +and assigns each element of $x'$ to the corresponding element of $b$. +If no such $x'$ exists, +then the elements of \tcode{b} are valid but unspecified. + +\pnum +\complexity +\bigoh{\tcode{A.extent(1)} \times \tcode{b.extent(0)}}. +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_vector_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-vector}@ InOutVec> + void triangular_matrix_vector_solve(InMat A, Triangle t, DiagonalStorage d, InOutVec b); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_vector_solve(A, t, d, b, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_vector_solve}% +\begin{itemdecl} +template + void triangular_matrix_vector_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutVec b); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_vector_solve(std::forward(exec), + A, t, d, b, divides{}); +\end{codeblock} +\end{itemdescr} + +\rSec3[linalg.algs.blas2.rank1]{Rank-1 (outer product) update of a matrix} + +\indexlibraryglobal{matrix_rank_1_update}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{inout-matrix}@ InOutMat> + void matrix_rank_1_update(InVec1 x, InVec2 y, InOutMat A); +template + void matrix_rank_1_update(ExecutionPolicy&& exec, InVec1 x, InVec2 y, InOutMat A); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform a nonsymmetric nonconjugated rank-1 update. +\begin{note} +These functions correspond to the BLAS functions +\tcode{xGER} (for real element types) and +\tcode{xGERU} (for complex element types)\supercite{blas2}. +\end{note} + +\pnum +\mandates +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}. + +\pnum +\expects +\tcode{\exposid{multipliable}(A, y, x)} is \tcode{true}. + +\pnum +\effects +Computes a matrix $A'$ such that $A' = A + x y^T$, +and assigns each element of $A'$ to the corresponding element of $A$. + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{y.extent(0)}}. +\end{itemdescr} + +\indexlibraryglobal{matrix_rank_1_update}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, @\exposconcept{inout-matrix}@ InOutMat> + void matrix_rank_1_update_c(InVec1 x, InVec2 y, InOutMat A); +template + void matrix_rank_1_update_c(ExecutionPolicy&& exec, InVec1 x, InVec2 y, InOutMat A); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform a nonsymmetric conjugated rank-1 update. +\begin{note} +These functions correspond to the BLAS functions +\tcode{xGER} (for real element types) and +\tcode{xGERC} (for complex element types)\supercite{blas2}. +\end{note} + +\pnum +\effects +\begin{itemize} +\item +For the overloads without an \tcode{ExecutionPolicy} argument, +equivalent to: +\begin{codeblock} +matrix_rank_1_update(x, conjugated(y), A); +\end{codeblock} +\item +otherwise, equivalent to: +\begin{codeblock} +matrix_rank_1_update(std::forward(exec), x, conjugated(y), A); +\end{codeblock} +\end{itemize} +\end{itemdescr} + +\rSec3[linalg.algs.blas2.symherrank1]{Symmetric or Hermitian Rank-1 (outer product) update of a matrix} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xSYR}, \tcode{xSPR}, \tcode{xHER}, and \tcode{xHPR}\supercite{blas2}. +They have overloads taking a scaling factor \tcode{alpha}, +because it would be impossible to express the update +$A = A - x x^T$ otherwise. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas2.symherrank1}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InOutMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 0)} +is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}, and +\item +\tcode{A.extent(0)} equals \tcode{x.extent(0)}. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{x.extent(0)}}. + +\indexlibraryglobal{symmetric_matrix_rank_1_update}% +\begin{itemdecl} +template + void symmetric_matrix_rank_1_update(Scalar alpha, InVec x, InOutMat A, Triangle t); +template + void symmetric_matrix_rank_1_update(ExecutionPolicy&& exec, + Scalar alpha, InVec x, InOutMat A, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a symmetric rank-1 update of the symmetric matrix \tcode{A}, +taking into account the \tcode{Triangle} parameter +that applies to \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes a matrix $A'$ such that +$A' = A + \alpha x x^T$, where the scalar $\alpha$ is \tcode{alpha}, +and assigns each element of $A'$ to the corresponding element of $A$. +\end{itemdescr} + +\indexlibraryglobal{symmetric_matrix_rank_1_update}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_1_update(InVec x, InOutMat A, Triangle t); +template + void symmetric_matrix_rank_1_update(ExecutionPolicy&& exec, InVec x, InOutMat A, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a symmetric rank-1 update of the symmetric matrix \tcode{A}, +taking into account the \tcode{Triangle} parameter +that applies to \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes a matrix $A'$ such that $A' = A + x x^T$ +and assigns each element of $A'$ to the corresponding element of $A$. +\end{itemdescr} + +\indexlibraryglobal{hermitian_matrix_rank_1_update}% +\begin{itemdecl} +template + void hermitian_matrix_rank_1_update(Scalar alpha, InVec x, InOutMat A, Triangle t); +template + void hermitian_matrix_rank_1_update(ExecutionPolicy&& exec, + Scalar alpha, InVec x, InOutMat A, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a Hermitian rank-1 update of the Hermitian matrix \tcode{A}, +taking into account the \tcode{Triangle} parameter +that applies to \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $A'$ such that +$A' = A + \alpha x x^H$, where the scalar $\alpha$ is \tcode{alpha}, +and assigns each element of $A'$ to the corresponding element of $A$. +\end{itemdescr} + +\indexlibraryglobal{hermitian_matrix_rank_1_update}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_1_update(InVec x, InOutMat A, Triangle t); +template + void hermitian_matrix_rank_1_update(ExecutionPolicy&& exec, InVec x, InOutMat A, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a Hermitian rank-1 update of the Hermitian matrix \tcode{A}, +taking into account the \tcode{Triangle} parameter +that applies to \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes a matrix $A'$ such that $A' = A + x x^H$ and +assigns each element of $A'$ to the corresponding element of $A$. +\end{itemdescr} + +\rSec3[linalg.algs.blas2.rank2]{Symmetric and Hermitian rank-2 matrix updates} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xSYR2},\tcode{xSPR2}, \tcode{xHER2} and \tcode{xHPR2}\supercite{blas2}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas2.rank2}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InOutMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}; and +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}, and +\item +\tcode{\exposid{multipliable}(A, x, y)} is \tcode{true}. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{x.extent(0)} \times \tcode{y.extent(0)}}. + +\indexlibraryglobal{symmetric_matrix_rank_2_update}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_2_update(InVec1 x, InVec2 y, InOutMat A, Triangle t); +template + void symmetric_matrix_rank_2_update(ExecutionPolicy&& exec, + InVec1 x, InVec2 y, InOutMat A, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a symmetric rank-2 update of the symmetric matrix \tcode{A}, +taking into account the \tcode{Triangle} parameter +that applies to \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $A'$ such that $A' = A + x y^T + y x^T$ and +assigns each element of $A'$ to the corresponding element of $A$. +\end{itemdescr} + +\indexlibraryglobal{hermitian_matrix_rank_2_update}% +\begin{itemdecl} +template<@\exposconcept{in-vector}@ InVec1, @\exposconcept{in-vector}@ InVec2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_2_update(InVec1 x, InVec2 y, InOutMat A, Triangle t); +template + void hermitian_matrix_rank_2_update(ExecutionPolicy&& exec, + InVec1 x, InVec2 y, InOutMat A, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a Hermitian rank-2 update of the Hermitian matrix \tcode{A}, +taking into account the \tcode{Triangle} parameter +that applies to \tcode{A}\iref{linalg.general}. + +\pnum +\effects +Computes $A'$ such that $A' = A + x y^H + y x^H$ and +assigns each element of $A'$ to the corresponding element of $A$. +\end{itemdescr} + +\rSec2[linalg.algs.blas3]{BLAS 3 algorithms} + +\rSec3[linalg.algs.blas3.gemm]{General matrix-matrix product} + +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xGEMM}\supercite{blas3}. +\end{note} + +\pnum +The following elements apply +to all functions in \ref{linalg.algs.blas3.gemm} +in addition to function-specific elements. + +\pnum +\mandates +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}. + +\pnum +\expects +\tcode{\exposid{multipliable}(A, B, C)} is \tcode{true}. + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{B.extent(1)}}. + +\indexlibraryglobal{matrix_product}% +\begin{itemdecl} + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void matrix_product(InMat1 A, InMat2 B, OutMat C); + template + void matrix_product(ExecutionPolicy&& exec, InMat1 A, InMat2 B, OutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Computes $C = A B$. +\end{itemdescr} + +\indexlibraryglobal{matrix_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, @\exposconcept{out-matrix}@ OutMat> + void matrix_product(InMat1 A, InMat2 B, InMat3 E, OutMat C); +template + void matrix_product(ExecutionPolicy&& exec, InMat1 A, InMat2 B, InMat3 E, OutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{\exposid{possibly-addable}()} is \tcode{true}. + +\pnum +\expects +\tcode{\exposid{addable}(E, E, C)} is \tcode{true}. + +\pnum +\effects +Computes $C = E + A B$. + +\pnum +\remarks +\tcode{C} may alias \tcode{E}. +\end{itemdescr} + +\rSec3[linalg.algs.blas3.xxmm]{Symmetric, Hermitian, and triangular matrix-matrix product} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xSYMM}, \tcode{xHEMM}, and \tcode{xTRMM}\supercite{blas3}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas3.xxmm} +in addition to function-specific elements. + +\pnum +\mandates +\begin{itemize} +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}, and +\item +\tcode{\exposid{possibly-addable}()} +is \tcode{true} for those overloads that take an \tcode{E} parameter. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(A, B, C)} is \tcode{true}, and +\item +\tcode{\exposid{addable}(E, E, C)} +is \tcode{true} for those overloads that take an \tcode{E} parameter. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{B.extent(1)}}. + +\indexlibraryglobal{symmetric_matrix_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, Triangle t, InMat2 B, OutMat C); +template + void symmetric_matrix_product(ExecutionPolicy&& exec, InMat1 A, Triangle t, InMat2 B, OutMat C); + +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, Triangle t, InMat2 B, OutMat C); +template + void hermitian_matrix_product(ExecutionPolicy&& exec, InMat1 A, Triangle t, InMat2 B, OutMat C); + +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, OutMat C); +template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, OutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform a matrix-matrix multiply, +taking into account +the \tcode{Triangle} and \tcode{Diagonal\-Storage} (if applicable) parameters +that apply to the symmetric, Hermitian, or triangular (respectively) matrix \tcode{A}\iref{linalg.general}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat1} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. + +\pnum +\effects +Computes $C = A B$. +\end{itemdescr} + +\indexlibraryglobal{symmetric_matrix_product}% +\begin{itemdecl} + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, InMat2 B, Triangle t, OutMat C); + template + void symmetric_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, InMat2 B, Triangle t, OutMat C); + template + void hermitian_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, OutMat C); + + template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, class DiagonalStorage, + @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, OutMat C); + template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, OutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform a matrix-matrix multiply, +taking into account +the \tcode{Triangle} and \tcode{Diagonal\-Storage} (if applicable) parameters +that apply to the symmetric, Hermitian, or triangular (respectively) matrix \tcode{B}\iref{linalg.general}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat2} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\tcode{B.extent(0) == B.extent(1)} is \tcode{true}. + +\pnum +\effects +Computes $C = A B$. +\end{itemdescr} + +\indexlibraryglobal{symmetric_matrix_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); +template + void symmetric_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); + +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); +template + void hermitian_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, InMat2 B, InMat3 E, OutMat C); + +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{in-matrix}@ InMat3, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, InMat3 E, + OutMat C); +template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, InMat2 B, InMat3 E, + OutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a potentially overwriting matrix-matrix multiply-add, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} (if applicable) parameters +that apply to the symmetric, Hermitian, or triangular (respectively) matrix \tcode{A}\iref{linalg.general}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat1} has \tcode{layout_blas_packed} layout, then the + layout's \tcode{Triangle} template argument has the same type as + the function's \tcode{Triangle} template argument; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. + +\pnum +\effects +Computes $C = E + A B$. + +\pnum +\remarks +\tcode{C} may alias \tcode{E}. +\end{itemdescr} + +\indexlibraryglobal{symmetric_matrix_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void symmetric_matrix_product(InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); +template + void symmetric_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); + +template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, @\exposconcept{in-matrix}@ InMat3, + @\exposconcept{out-matrix}@ OutMat> + void hermitian_matrix_product(InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); +template + void hermitian_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, InMat3 E, OutMat C); + +template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat3, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_product(InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, InMat3 E, + OutMat C); +template + void triangular_matrix_product(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, Triangle t, DiagonalStorage d, InMat3 E, + OutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform +a potentially overwriting matrix-matrix multiply-add, +taking into account +the \tcode{Triangle} and \tcode{Diagonal\-Storage} (if applicable) parameters +that apply to the symmetric, Hermitian, or triangular (respectively) matrix \tcode{B}\iref{linalg.general}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat2} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\tcode{B.extent(0) == B.extent(1)} is \tcode{true}. + +\pnum +\effects +Computes $C = E + A B$. + +\pnum +\remarks +\tcode{C} may alias \tcode{E}. +\end{itemdescr} + +\rSec3[linalg.algs.blas3.trmm]{In-place triangular matrix-matrix product} + +\pnum +These functions perform +an in-place matrix-matrix multiply, +taking into account +the \tcode{Triangle} and \tcode{Diagonal\-Storage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. +\begin{note} +These functions correspond to the BLAS function \tcode{xTRMM}\supercite{blas3}. +\end{note} + +\indexlibraryglobal{triangular_matrix_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_left_product(InMat A, Triangle t, DiagonalStorage d, InOutMat C); +template + void triangular_matrix_left_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(A, C, C)} is \tcode{true}, and +\item +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Computes a matrix $C'$ such that $C' = A C$ and +assigns each element of $C'$ to the corresponding element of $C$. + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{C.extent(0)}}. +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_right_product}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_right_product(InMat A, Triangle t, DiagonalStorage d, InOutMat C); +template + void triangular_matrix_right_product(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, InOutMat C); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(C, A, C)} is \tcode{true}, and +\item +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Computes a matrix $C'$ such that $C' = C A$ and +assigns each element of $C'$ to the corresponding element of $C$. + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{C.extent(0)}}. +\end{itemdescr} + +\rSec3[linalg.algs.blas3.rankk]{Rank-k update of a symmetric or Hermitian matrix} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xSYRK} and \tcode{xHERK}\supercite{blas3}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas3.rankk}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InOutMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}; +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 0)} +is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}, +\item +\tcode{C.extent(0)} equals \tcode{C.extent(1)}, and +\item +\tcode{A.extent(0)} equals \tcode{C.extent(0)}. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{C.extent(0)}}. + +\indexlibraryglobal{symmetric_matrix_rank_k_update}% +\begin{itemdecl} + template + void symmetric_matrix_rank_k_update(Scalar alpha, InMat A, InOutMat C, Triangle t); + template + void symmetric_matrix_rank_k_update(ExecutionPolicy&& exec, + Scalar alpha, InMat A, InOutMat C, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Computes a matrix $C'$ such that $C' = C + \alpha A A^T$, +where the scalar $\alpha$ is \tcode{alpha}, +and assigns each element of $C'$ to the corresponding element of $C$. +\end{itemdescr} + +\indexlibraryglobal{symmetric_matrix_rank_k_update}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_k_update(InMat A, InOutMat C, Triangle t); +template + void symmetric_matrix_rank_k_update(ExecutionPolicy&& exec, + InMat A, InOutMat C, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Computes a matrix $C'$ such that $C' = C + A A^T$, and +assigns each element of $C'$ to the corresponding element of $C$. +\end{itemdescr} + +\indexlibraryglobal{hermitian_matrix_rank_k_update}% +\begin{itemdecl} +template + void hermitian_matrix_rank_k_update(Scalar alpha, InMat A, InOutMat C, Triangle t); +template + void hermitian_matrix_rank_k_update(ExecutionPolicy&& exec, + Scalar alpha, InMat A, InOutMat C, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Computes a matrix $C'$ such that $C' = C + \alpha A A^H$, +where the scalar $\alpha$ is \tcode{alpha}, +and assigns each element of $C'$ to the corresponding element of $C$. +\end{itemdescr} + +\indexlibraryglobal{hermitian_matrix_rank_k_update}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_k_update(InMat A, InOutMat C, Triangle t); +template + void hermitian_matrix_rank_k_update(ExecutionPolicy&& exec, + InMat A, InOutMat C, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Computes a matrix $C'$ such that $C' = C + A A^H$, and +assigns each element of $C'$ to the corresponding element of $C$. +\end{itemdescr} + +\rSec3[linalg.algs.blas3.rank2k]{Rank-2k update of a symmetric or Hermitian matrix} + +\pnum +\begin{note} +These functions correspond to the BLAS functions +\tcode{xSYR2K} and \tcode{xHER2K}\supercite{blas3}. +\end{note} + +\pnum +The following elements apply to all functions in \ref{linalg.algs.blas3.rank2k}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InOutMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{possibly-addable}()} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{addable}(A, B, C)} is \tcode{true}, and +\item +\tcode{A.extent(0)} equals \tcode{A.extent(1)}. +\end{itemize} + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{C.extent(0)}}. + +\indexlibraryglobal{symmetric_matrix_rank_2k_update}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void symmetric_matrix_rank_2k_update(InMat1 A, InMat2 B, InOutMat C, Triangle t); +template + void symmetric_matrix_rank_2k_update(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, InOutMat C, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Computes a matrix $C'$ such that $C' = C + A B^T + B A^T$, +and assigns each element of $C'$ to the corresponding element of $C$. +\end{itemdescr} + +\indexlibraryglobal{hermitian_matrix_rank_2k_update}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, @\exposconcept{in-matrix}@ InMat2, + @\exposconcept{possibly-packed-inout-matrix}@ InOutMat, class Triangle> + void hermitian_matrix_rank_2k_update(InMat1 A, InMat2 B, InOutMat C, Triangle t); +template + void hermitian_matrix_rank_2k_update(ExecutionPolicy&& exec, + InMat1 A, InMat2 B, InOutMat C, Triangle t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Computes a matrix $C'$ such that $C' = C + A B^H + B A^H$, +and assigns each element of $C'$ to the corresponding element of $C$. +\end{itemdescr} + +\rSec3[linalg.algs.blas3.trsm]{Solve multiple triangular linear systems} + +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xTRSM}\supercite{blas3}. +\end{note} + +\indexlibraryglobal{triangular_matrix_matrix_left_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat, class BinaryDivideOp> + void triangular_matrix_matrix_left_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); +template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform multiple matrix solves, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat1} has \tcode{layout_blas_packed} layout, then the + layout's \tcode{Triangle} template argument has the same type as + the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(A, X, B)} is \tcode{true}, and +\item +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Computes $X'$ such that $AX' = B$, +and assigns each element of $X'$ to the corresponding element of $X$. +If no such $X'$ exists, +then the elements of \tcode{X} are valid but unspecified. + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{X.extent(1)} \times \tcode{X.extent(1)}}. +\end{itemdescr} + +\pnum +\begin{note} +Since the triangular matrix is on the left, +the desired \tcode{divide} implementation +in the case of noncommutative multiplication +is mathematically equivalent to $y^{-1} x$, +where $x$ is the first argument and $y$ is the second argument, +and $y^{-1}$ denotes the multiplicative inverse of $y$. +\end{note} + +\indexlibraryglobal{triangular_matrix_matrix_left_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_matrix_left_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_left_solve(A, t, d, B, X, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_left_solve}% +\begin{itemdecl} +template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_left_solve(std::forward(exec), + A, t, d, B, X, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_right_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat, class BinaryDivideOp> + void triangular_matrix_matrix_right_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); +template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X, BinaryDivideOp divide); +\end{itemdecl} + +\begin{itemdescr} + +\pnum +These functions perform multiple matrix solves, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat1} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{possibly-multipliable}()} is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0,1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(X, A, B)} is \tcode{true}, and +\item +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Computes $X'$ such that $X'A = B$, +and assigns each element of $X'$ to the corresponding element of $X$. +If no such $X'$ exists, +then the elements of \tcode{X} are valid but unspecified. + +\pnum +\complexity +$O($ \tcode{B.extent(0)} $\cdot$ \tcode{B.extent(1)} $\cdot$ \tcode{A.extent(1)} $)$ +\begin{note} +Since the triangular matrix is on the right, +the desired \tcode{divide} implementation +in the case of noncommutative multiplication +is mathematically equivalent to $x y^{-1}$, +where $x$ is the first argument and $y$ is the second argument, +and $y^{-1}$ denotes the multiplicative inverse of $y$. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_right_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat1, class Triangle, class DiagonalStorage, + @\exposconcept{in-matrix}@ InMat2, @\exposconcept{out-matrix}@ OutMat> + void triangular_matrix_matrix_right_solve(InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_right_solve(A, t, d, B, X, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_right_solve}% +\begin{itemdecl} +template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat1 A, Triangle t, DiagonalStorage d, + InMat2 B, OutMat X); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_right_solve(std::forward(exec), + A, t, d, B, X, divides{}); +\end{codeblock} +\end{itemdescr} + +\rSec3[linalg.algs.blas3.inplacetrsm]{Solve multiple triangular linear systems in-place} + +\pnum +\begin{note} +These functions correspond to the BLAS function \tcode{xTRSM}\supercite{blas3}. +\end{note} + +\indexlibraryglobal{triangular_matrix_matrix_left_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{inout-matrix}@ InOutMat, class BinaryDivideOp> + void triangular_matrix_matrix_left_solve(InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); +template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform multiple in-place matrix solves, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. +\begin{note} +This algorithm makes it possible +to compute factorizations like Cholesky and LU in place. +Performing triangular solve in place hinders parallelization. +However, other \tcode{ExecutionPolicy} specific optimizations, +such as vectorization, are still possible. +\end{note} + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} +is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(A, B, B)} is \tcode{true}, and +\item +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Computes $X'$ such that $AX' = B$, +and assigns each element of $X'$ to the corresponding element of $B$. +If so such $X'$ exists, +then the elements of \tcode{B} are valid but unspecified. + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{B.extent(1)}}. +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_left_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_matrix_left_solve(InMat A, Triangle t, DiagonalStorage d, + InOutMat B); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_left_solve(A, t, d, B, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_left_solve}% +\begin{itemdecl} + template + void triangular_matrix_matrix_left_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_left_solve(std::forward(exec), + A, t, d, B, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_right_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, + @\exposconcept{inout-matrix}@ InOutMat, class BinaryDivideOp> + void triangular_matrix_matrix_right_solve(InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); +template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B, BinaryDivideOp divide); +\end{itemdecl} + +\begin{itemdescr} +\pnum +These functions perform multiple in-place matrix solves, +taking into account the \tcode{Triangle} and \tcode{DiagonalStorage} parameters +that apply to the triangular matrix \tcode{A}\iref{linalg.general}. +\begin{note} +This algorithm makes it possible +to compute factorizations like Cholesky and LU in place. +Performing triangular solve in place hinders parallelization. +However, other \tcode{ExecutionPolicy} specific optimizations, +such as vectorization, are still possible. +\end{note} + +\pnum +\mandates +\begin{itemize} +\item +If \tcode{InMat} has \tcode{layout_blas_packed} layout, +then the layout's \tcode{Triangle} template argument has +the same type as the function's \tcode{Triangle} template argument; +\item +\tcode{\exposid{possibly-multipliable}()} +is \tcode{true}; and +\item +\tcode{\exposid{compatible-static-extents}(0, 1)} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item +\tcode{\exposid{multipliable}(B, A, B)} is \tcode{true}, and +\item +\tcode{A.extent(0) == A.extent(1)} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Computes $X'$ such that $X'A = B$, +and assigns each element of $X'$ to the corresponding element of $B$. +If so such $X'$ exists, +then the elements of \tcode{B} are valid but unspecified. + +\pnum +\complexity +\bigoh{\tcode{A.extent(0)} \times \tcode{A.extent(1)} \times \tcode{B.extent(1)}}. +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_right_solve}% +\begin{itemdecl} +template<@\exposconcept{in-matrix}@ InMat, class Triangle, class DiagonalStorage, @\exposconcept{inout-matrix}@ InOutMat> + void triangular_matrix_matrix_right_solve(InMat A, Triangle t, DiagonalStorage d, InOutMat B); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_right_solve(A, t, d, B, divides{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{triangular_matrix_matrix_right_solve}% +\begin{itemdecl} +template + void triangular_matrix_matrix_right_solve(ExecutionPolicy&& exec, + InMat A, Triangle t, DiagonalStorage d, + InOutMat B); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +triangular_matrix_matrix_right_solve(std::forward(exec), + A, t, d, B, divides{}); +\end{codeblock} +\end{itemdescr} + +\rSec1[simd]{Data-parallel types} + +\rSec2[simd.general]{General} + +\pnum +Subclause \ref{simd} defines data-parallel types and operations on these types. +\begin{note} +The intent is to support acceleration through data-parallel execution resources +where available, such as SIMD registers and instructions or execution units +driven by a common instruction decoder. +SIMD stands for ``Single Instruction Stream -- Multiple Data Stream''; +it is defined in Flynn 1966\supercite{flynn-taxonomy}. +\end{note} + +\pnum +The set of \defnadjx{vectorizable}{types}{type} comprises +\begin{itemize} + \item + all standard integer types, character types, and the types \tcode{float} and + \tcode{double}\iref{basic.fundamental}; + \item + \tcode{std::float16_t}, \tcode{std::float32_t}, and \tcode{std::float64_t} + if defined\iref{basic.extended.fp}; and + \item + \tcode{complex} where \tcode{T} is a vectorizable floating-point type. +\end{itemize} + +\pnum +The term \defnadj{data-parallel}{type} refers to all enabled specializations of +the \tcode{basic_simd} and \tcode{basic_simd_mask} class templates. +A \defnadj{data-parallel}{object} is an object of data-parallel type. + +\pnum +Each specialization of \tcode{basic_simd} or \tcode{basic_simd_mask} is either +enabled or disabled, as described in \ref{simd.overview} and +\ref{simd.mask.overview}. + +\pnum +A data-parallel type consists of one or more elements of an underlying +vectorizable type, called the \defnadj{element}{type}. +The number of elements is a constant for each data-parallel type and called the +\defn{width} of that type. +The elements in a data-parallel type are indexed from 0 to $\textrm{width} - 1$. + +\pnum +An \defnadj{element-wise}{operation} applies a specified operation to the +elements of one or more data-parallel objects. +Each such application is unsequenced with respect to the others. +A \defnadj{unary element-wise}{operation} is an element-wise operation that +applies a unary operation to each element of a data-parallel object. +A \defnadj{binary element-wise}{operation} is an element-wise operation that +applies a binary operation to corresponding elements of two data-parallel +objects. + +\pnum +Given a \tcode{basic_simd_mask} object \tcode{mask}, the +\defnadj{selected}{indices} signify the integers $i$ in the range +\range{0}{mask.size()} for which \tcode{mask[$i$]} is \tcode{true}. +Given a data-parallel object \tcode{data}, the \defnadj{selected}{elements} +signify the elements \tcode{data[$i$]} for all selected indices $i$. + +\pnum +The conversion from an arithmetic type \tcode{U} to a vectorizable type +\tcode{T} is \defn{value-preserving} if all possible values of \tcode{U} can be +represented with type \tcode{T}. + +\rSec2[simd.expos]{Exposition-only types, variables, and concepts} + +\begin{codeblock} +using @\exposidnc{simd-size-type} = \seebelownc@; // \expos +template using @\exposidnc{integer-from} = \seebelownc@; // \expos + +template + constexpr @\exposidnc{simd-size-type} \exposidnc{simd-size-v} = \seebelownc@; // \expos +template constexpr size_t @\exposidnc{mask-element-size} = \seebelownc@; // \expos + +template + concept @\defexposconceptnc{constexpr-wrapper-like}@ = // \expos + @\libconcept{convertible_to}@ && + @\libconcept{equality_comparable_with}@ && + bool_constant::value && + bool_constant(T()) == T::value>::value; + +template using @\exposidnc{deduced-simd-t} = \seebelownc@; // \expos + +template using @\exposidnc{make-compatible-simd-t} = \seebelownc@; // \expos + +template + concept @\defexposconceptnc{simd-type}@ = // \expos + @\libconcept{same_as}@> && + is_default_constructible_v; + +template + concept @\defexposconceptnc{simd-floating-point}@ = // \expos + @\exposconcept{simd-type}@ && @\libconcept{floating_point}@; + +template + using @\exposidnc{simd-complex-value-type}@ = typename V::value_type::value_type; // \expos + +template + concept @\defexposconceptnc{simd-complex}@ = // \expos + @\exposconcept{simd-type}@ && @\libconcept{same_as}@>>; + +template + concept @\defexposconceptnc{math-floating-point}@ = // \expos + (@\exposconceptnc{simd-floating-point}<\exposidnc{deduced-simd-t}@> || ...); + +template + requires @\exposconceptnc{math-floating-point}@ + using @\exposidnc{math-common-simd-t} = \seebelownc@; // \expos + +template + concept @\exposconceptnc{reduction-binary-operation} = \seebelownc@; // \expos + +// \ref{simd.expos.abi}, \tcode{simd} ABI tags +template using @\exposidnc{native-abi} = \seebelownc@; // \expos +template using @\exposidnc{deduce-abi-t} = \seebelownc@; // \expos + +// \ref{simd.flags}, Load and store flags +struct @\exposidnc{convert-flag}@; // \expos +struct @\exposidnc{aligned-flag}@; // \expos +template struct @\exposidnc{overaligned-flag}@; // \expos +\end{codeblock} + +\rSec3[simd.expos.defn]{Exposition-only helpers} + +\begin{itemdecl} +using @\exposid{simd-size-type}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\exposid{simd-size-type} is an alias for a signed integer type. +\end{itemdescr} + +\begin{itemdecl} +template using @\exposid{integer-from}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{\exposid{integer-from}} is an alias for a signed integer type +\tcode{T} such that \tcode{sizeof(T)} equals \tcode{Bytes}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr @\exposid{simd-size-type} \exposid{simd-size-v}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{\exposid{simd-size-v}} denotes the width of \tcode{basic_simd} if the specialization \tcode{basic_simd} is enabled, or \tcode{0} +otherwise. +\end{itemdescr} + +\begin{itemdecl} +template constexpr size_t @\exposid{mask-element-size}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{\exposid{mask-element-size}>} has the value +\tcode{Bytes}. +\end{itemdescr} + +\begin{itemdecl} +template using @\exposid{deduced-simd-t}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{x} denote an lvalue of type \tcode{const T}. + +\pnum +\tcode{\exposid{deduced-simd-t}} is an alias for +\begin{itemize} + \item + \tcode{decltype(x + x)}, if the type of \tcode{x + x} is an enabled + specialization of \tcode{basic_simd}; otherwise + \item + \tcode{void}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template using @\exposid{make-compatible-simd-t}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{x} denote an lvalue of type \tcode{const T}. +\pnum +\tcode{\exposid{make-compatible-simd-t}} is an alias for +\begin{itemize} + \item + \tcode{\exposid{deduced-simd-t}}, if that type is not \tcode{void}, + otherwise + \item + \tcode{simd}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + requires @\exposconcept{math-floating-point}@ + using @\exposid{math-common-simd-t}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{T0} denote \tcode{Ts...[0]}. +Let \tcode{T1} denote \tcode{Ts...[1]}. +Let \tcode{TRest} denote a pack such that \tcode{T0, T1, TRest...} is equivalent +to \tcode{Ts...}. + +\pnum +Let \tcode{\exposid{math-common-simd-t}} be an alias for +\begin{itemize} + \item + \tcode{\exposid{deduced-simd-t}}, if \tcode{sizeof...(Ts)} equals $1$; + otherwise + \item + \tcode{common_type_t<\exposid{deduced-simd-t}, + \exposid{deduced-simd-t}>}, if \tcode{sizeof...(Ts)} equals $2$ and + \tcode{\exposconcept{math-floating-point} \&\& + \exposconcept{math-floating-point}} is \tcode{true}; otherwise + \item + \tcode{common_type_t<\exposid{deduced-simd-t}, T1>}, if + \tcode{sizeof...(Ts)} equals $2$ and + \tcode{\exposconceptx{math-floating-\brk{}point}{math-floating-point}<\brk{}T0>} + is \tcode{true}; otherwise + \item + \tcode{common_type_t>}, if + \tcode{sizeof...(Ts)} equals $2$; otherwise + \item + \tcode{common_type_t<\exposid{math-common-simd-t}, TRest...>}, if + \tcode{\exposid{math-common-simd-t}} is valid and denotes a type; + otherwise + \item + \tcode{common_type_t<\exposid{math-common-simd-t}, T0, T1>}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + concept @\defexposconcept{reduction-binary-operation}@ = + requires (const BinaryOperation binary_op, const simd v) { + { binary_op(v, v) } -> @\libconcept{same_as}@>; + }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Types \tcode{BinaryOperation} and \tcode{T} model +\tcode{\exposconcept{reduction-binary-operation}} only if: +\begin{itemize} +\item \tcode{BinaryOperation} is a binary element-wise operation and the +operation is commutative. + +\item An object of type \tcode{BinaryOperation} can be invoked with two +arguments of type \tcode{basic_simd}, with unspecified ABI tag +\tcode{Abi}, returning a \tcode{basic_simd}. +\end{itemize} +\end{itemdescr} + +\rSec3[simd.expos.abi]{\tcode{simd} ABI tags} + +\begin{itemdecl} +template using @\exposid{native-abi}@ = @\seebelow@; +template using @\exposid{deduce-abi-t}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +An \defn{ABI tag} is a type that indicates a choice of size and binary +representation for objects of data-parallel type. +\begin{note} +The intent is for the size and binary representation to depend on the target +architecture and compiler flags. +The ABI tag, together with a given element type, implies the width. +\end{note} + +\pnum +\begin{note} +The ABI tag is orthogonal to selecting the machine instruction set. +The selected machine instruction set limits the usable ABI tag types, though +(see \ref{simd.overview}). +The ABI tags enable users to safely pass objects of data-parallel type between +translation unit boundaries (e.g., function calls or I/O). +\end{note} + +\pnum +An implementation defines ABI tag types as necessary for the following aliases. + +\pnum +\tcode{\exposid{deduce-abi-t}} is defined if +\begin{itemize} +\item \tcode{T} is a vectorizable type, +\item \tcode{N} is greater than zero, and +\item \tcode{N} is not larger than an implementation-defined maximum. +\end{itemize} +The \impldef{maximum width for \tcode{simd} and \tcode{simd_mask}} maximum for +\tcode{N} is not smaller than 64 and can differ depending on \tcode{T}. + +\pnum +Where present, \tcode{\exposid{deduce-abi-t}} names an ABI tag type such +that +\begin{itemize} + \item + \tcode{\exposid{simd-size-v}>} equals + \tcode{N}, \item \tcode{basic_simd>} is + enabled\iref{simd.overview}, and + \item + \tcode{basic_simd_mask, N>>} is enabled. +\end{itemize} + +\pnum +\tcode{\exposid{native-abi}} is an \impldef{default ABI tag for +\tcode{basic_simd} and \tcode{basic_simd_mask}} alias for an ABI tag. +\tcode{basic_simd>} is an enabled specialization. +\begin{note} +The intent is to use the ABI tag producing the most efficient data-parallel +execution for the element type \tcode{T} on the currently targeted system. +For target architectures with ISA extensions, compiler flags can change the type +of the \tcode{\exposid{native-abi}} alias. +\end{note} +\begin{example} +Consider a target architecture supporting the ABI tags \tcode{__simd128} and +\tcode{__simd256}, where hardware support for \tcode{__simd256} exists only for +floating-point types. +The implementation therefore defines \tcode{\exposid{native-abi}} as an alias +for +\begin{itemize} +\item \tcode{__simd256} if \tcode{T} is a floating-point type, and +\item \tcode{__simd128} otherwise. +\end{itemize} +\end{example} +\end{itemdescr} + +\rSec2[simd.syn]{Header \tcode{} synopsis} +\indexheader{simd}% +\begin{codeblock} +namespace std::datapar { + // \ref{simd.traits}, \tcode{simd} type traits + template struct alignment; + template + constexpr size_t alignment_v = alignment::value; + + template struct rebind { using type = @\seebelow@; }; + template using rebind_t = typename rebind::type; + template<@\exposid{simd-size-type}@ N, class V> struct resize { using type = @\seebelow@; }; + template<@\exposid{simd-size-type}@ N, class V> using resize_t = typename resize::type; + + // \ref{simd.flags}, Load and store flags + template struct flags; + inline constexpr flags<> flag_default{}; + inline constexpr flags<@\exposid{convert-flag}@> flag_convert{}; + inline constexpr flags<@\exposid{aligned-flag}@> flag_aligned{}; + template requires (has_single_bit(N)) + constexpr flags<@\exposid{overaligned-flag}@> flag_overaligned{}; + + // \ref{simd.class}, Class template \tcode{basic_simd} + template> class basic_simd; + template>> + using simd = basic_simd>; + + // \ref{simd.mask.class}, Class template \tcode{basic_simd_mask} + template>> class basic_simd_mask; + template>> + using simd_mask = basic_simd_mask>; + + // \ref{simd.loadstore}, \tcode{basic_simd} load and store functions + template + requires ranges::@\libconcept{sized_range}@ + constexpr V unchecked_load(R&& r, flags f = {}); + template + requires ranges::@\libconcept{sized_range}@ + constexpr V unchecked_load(R&& r, const typename V::mask_type& k, + flags f = {}); + template + constexpr V unchecked_load(I first, iter_difference_t n, + flags f = {}); + template + constexpr V unchecked_load(I first, iter_difference_t n, + const typename V::mask_type& k, flags f = {}); + template S, class... Flags> + constexpr V unchecked_load(I first, S last, flags f = {}); + template S, class... Flags> + constexpr V unchecked_load(I first, S last, const typename V::mask_type& k, + flags f = {}); + + template + requires ranges::@\libconcept{sized_range}@ + constexpr V partial_load(R&& r, flags f = {}); + template + requires ranges::@\libconcept{sized_range}@ + constexpr V partial_load(R&& r, const typename V::mask_type& k, + flags f = {}); + template + constexpr V partial_load(I first, iter_difference_t n, flags f = {}); + template + constexpr V partial_load(I first, iter_difference_t n, + const typename V::mask_type& k, flags f = {}); + template S, class... Flags> + constexpr V partial_load(I first, S last, flags f = {}); + template S, class... Flags> + constexpr V partial_load(I first, S last, const typename V::mask_type& k, + flags f = {}); + + template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void unchecked_store(const basic_simd& v, R&& r, + flags f = {}); + template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void unchecked_store(const basic_simd& v, R&& r, + const typename basic_simd::mask_type& mask, flags f = {}); + template + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, + iter_difference_t n, flags f = {}); + template + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, + iter_difference_t n, const typename basic_simd::mask_type& mask, + flags f = {}); + template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, S last, + flags f = {}); + template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, S last, + const typename basic_simd::mask_type& mask, flags f = {}); + + template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void partial_store(const basic_simd& v, R&& r, + flags f = {}); + template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void partial_store(const basic_simd& v, R&& r, + const typename basic_simd::mask_type& mask, flags f = {}); + template + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store( + const basic_simd& v, I first, iter_difference_t n, flags f = {}); + template + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store( + const basic_simd& v, I first, iter_difference_t n, + const typename basic_simd::mask_type& mask, flags f = {}); + template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store(const basic_simd& v, I first, S last, + flags f = {}); + template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store(const basic_simd& v, I first, S last, + const typename basic_simd::mask_type& mask, flags f = {}); + + // \ref{simd.creation}, \tcode{basic_simd} and \tcode{basic_simd_mask} creation + template + constexpr auto chunk(const basic_simd& x) noexcept; + template + constexpr auto chunk(const basic_simd_mask<@\exposid{mask-element-size}@, Abi>& x) noexcept; + + template + constexpr auto chunk(const basic_simd& x) noexcept; + template + constexpr auto chunk(const basic_simd_mask& x) noexcept; + + template + constexpr basic_simd::size() + ...)>> + cat(const basic_simd&...) noexcept; + template + constexpr basic_simd_mask, + (basic_simd_mask::size() + ...)>> + cat(const basic_simd_mask&...) noexcept; + + // \ref{simd.mask.reductions}, \tcode{basic_simd_mask} reductions + template + constexpr bool all_of(const basic_simd_mask&) noexcept; + template + constexpr bool any_of(const basic_simd_mask&) noexcept; + template + constexpr bool none_of(const basic_simd_mask&) noexcept; + template + constexpr @\exposid{simd-size-type}@ reduce_count(const basic_simd_mask&) noexcept; + template + constexpr @\exposid{simd-size-type}@ reduce_min_index(const basic_simd_mask&); + template + constexpr @\exposid{simd-size-type}@ reduce_max_index(const basic_simd_mask&); + + constexpr bool all_of(@\libconcept{same_as}@ auto) noexcept; + constexpr bool any_of(@\libconcept{same_as}@ auto) noexcept; + constexpr bool none_of(@\libconcept{same_as}@ auto) noexcept; + constexpr @\exposid{simd-size-type}@ reduce_count(@\libconcept{same_as}@ auto) noexcept; + constexpr @\exposid{simd-size-type}@ reduce_min_index(@\libconcept{same_as}@ auto); + constexpr @\exposid{simd-size-type}@ reduce_max_index(@\libconcept{same_as}@ auto); + + // \ref{simd.reductions}, \tcode{basic_simd} reductions + template> + constexpr T reduce(const basic_simd&, BinaryOperation = {}); + template> + constexpr T reduce( + const basic_simd& x, const typename basic_simd::mask_type& mask, + BinaryOperation binary_op = {}, type_identity_t identity_element = @\seebelow@); + + template + constexpr T reduce_min(const basic_simd&) noexcept; + template + constexpr T reduce_min(const basic_simd&, + const typename basic_simd::mask_type&) noexcept; + template + constexpr T reduce_max(const basic_simd&) noexcept; + template + constexpr T reduce_max(const basic_simd&, + const typename basic_simd::mask_type&) noexcept; + + // \ref{simd.alg}, Algorithms + template + constexpr basic_simd + min(const basic_simd& a, const basic_simd& b) noexcept; + template + constexpr basic_simd + max(const basic_simd& a, const basic_simd& b) noexcept; + template + constexpr pair, basic_simd> + minmax(const basic_simd& a, const basic_simd& b) noexcept; + template + constexpr basic_simd + clamp(const basic_simd& v, const basic_simd& lo, + const basic_simd& hi); + + template + constexpr auto select(bool c, const T& a, const U& b) + -> remove_cvref_t; + template + constexpr auto select(const basic_simd_mask& c, const T& a, const U& b) + noexcept -> decltype(@\exposid{simd-select-impl}@(c, a, b)); + + // \ref{simd.math}, Mathematical functions + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ acos(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ asin(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ atan(const V& x); + template + constexpr @\exposid{math-common-simd-t}@ atan2(const V0& y, const V1& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ cos(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ sin(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ tan(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ acosh(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ asinh(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ atanh(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ cosh(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ sinh(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ tanh(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ exp(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ exp2(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ expm1(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ + frexp(const V& value, rebind_t>* exp); + template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> ilogb(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ ldexp(const V& x, const + rebind_t>& exp); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log10(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log1p(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log2(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ logb(const V& x); + template + constexpr basic_simd modf(const type_identity_t>& value, + basic_simd* iptr); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ scalbn(const V& x, const + rebind_t>& n); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ scalbln( + const V& x, const rebind_t>& n); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ cbrt(const V& x); + template<@\libconcept{signed_integral}@ T, class Abi> + constexpr basic_simd abs(const basic_simd& j); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ abs(const V& j); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ fabs(const V& x); + template + constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y, const V2& z); + template + constexpr @\exposid{math-common-simd-t}@ pow(const V0& x, const V1& y); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ sqrt(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ erf(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ erfc(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ lgamma(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ tgamma(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ ceil(const V& x); + template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ floor(const V& x); + template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ nearbyint(const V& x); + template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ rint(const V& x); + template<@\exposconcept{math-floating-point}@ V> + rebind_t> lrint(const V& x); + template<@\exposconcept{math-floating-point}@ V> + rebind_t llrint(const @\exposid{deduced-simd-t}@& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ round(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> lround(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> llround(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ trunc(const V& x); + template + constexpr @\exposid{math-common-simd-t}@ fmod(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ remainder(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ + remquo(const V0& x, const V1& y, rebind_t>* quo); + template + constexpr @\exposid{math-common-simd-t}@ copysign(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ nextafter(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ fdim(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ fmax(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ fmin(const V0& x, const V1& y); + template + constexpr @\exposid{math-common-simd-t}@ fma(const V0& x, const V1& y, const V2& z); + template + constexpr @\exposid{math-common-simd-t}@ + lerp(const V0& a, const V1& b, const V2& t) noexcept; + template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> fpclassify(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isfinite(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isinf(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isnan(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isnormal(const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type signbit(const V& x); + template + constexpr typename @\exposid{math-common-simd-t}@::mask_type + isgreater(const V0& x, const V1& y); + template + constexpr typename @\exposid{math-common-simd-t}@::mask_type + isgreaterequal(const V0& x, const V1& y); + template + constexpr typename @\exposid{math-common-simd-t}@::mask_type + isless(const V0& x, const V1& y); + template + constexpr typename @\exposid{math-common-simd-t}@::mask_type + islessequal(const V0& x, const V1& y); + template + constexpr typename @\exposid{math-common-simd-t}@::mask_type + islessgreater(const V0& x, const V1& y); + template + constexpr typename @\exposid{math-common-simd-t}@::mask_type + isunordered(const V0& x, const V1& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ assoc_laguerre(const rebind_t>& n, const + rebind_t>& m, + const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ assoc_legendre(const rebind_t>& l, const + rebind_t>& m, + const V& x); + template + @\exposid{math-common-simd-t}@ beta(const V0& x, const V1& y); + template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ comp_ellint_1(const V& k); + template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ comp_ellint_2(const V& k); + template + @\exposid{math-common-simd-t}@ comp_ellint_3(const V0& k, const V1& nu); + template + @\exposid{math-common-simd-t}@ cyl_bessel_i(const V0& nu, const V1& x); + template + @\exposid{math-common-simd-t}@ cyl_bessel_j(const V0& nu, const V1& x); + template + @\exposid{math-common-simd-t}@ cyl_bessel_k(const V0& nu, const V1& x); + template + @\exposid{math-common-simd-t}@ cyl_neumann(const V0& nu, const V1& x); + template + @\exposid{math-common-simd-t}@ ellint_1(const V0& k, const V1& phi); + template + @\exposid{math-common-simd-t}@ ellint_2(const V0& k, const V1& phi); + template + @\exposid{math-common-simd-t}@ ellint_3(const V0& k, const V1& nu, const V2& phi); + template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ expint(const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ hermite(const rebind_t>& n, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ laguerre(const rebind_t>& n, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ legendre(const rebind_t>& l, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ riemann_zeta(const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ sph_bessel( + const rebind_t>& n, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ sph_legendre(const rebind_t>& l, + const rebind_t>& m, const V& theta); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ + sph_neumann(const rebind_t>& n, const V& x); + + // \ref{simd.bit}, Bit manipulation + template<@\exposconcept{simd-type}@ V> constexpr V byteswap(const V& v) noexcept; + template<@\exposconcept{simd-type}@ V> constexpr V bit_ceil(const V& v) noexcept; + template<@\exposconcept{simd-type}@ V> constexpr V bit_floor(const V& v) noexcept; + + template<@\exposconcept{simd-type}@ V> + constexpr typename V::mask_type has_single_bit(const V& v) noexcept; + + template<@\exposconcept{simd-type}@ V0, @\exposconcept{simd-type}@ V1> + constexpr V0 rotl(const V0& v, const V1& s) noexcept; + template<@\exposconcept{simd-type}@ V> + constexpr V rotl(const V& v, int s) noexcept; + + template<@\exposconcept{simd-type}@ V0, @\exposconcept{simd-type}@ V1> + constexpr V0 rotr(const V0& v, const V1& s) noexcept; + template<@\exposconcept{simd-type}@ V> + constexpr V rotr(const V& v, int s) noexcept; + + template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> bit_width(const V& v) noexcept; + template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> + countl_zero(const V& v) noexcept; + template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> countl_one(const V& v) noexcept; + template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> + countr_zero(const V& v) noexcept; + template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> countr_one(const V& v) noexcept; + template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> popcount(const V& v) noexcept; + + // \ref{simd.complex.math}, simd complex math + template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> real(const V&) noexcept; + + template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> imag(const V&) noexcept; + + template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> abs(const V&); + + template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> arg(const V&); + + template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> norm(const V&); + + template<@\exposconcept{simd-complex}@ V> constexpr V conj(const V&); + template<@\exposconcept{simd-complex}@ V> constexpr V proj(const V&); + template<@\exposconcept{simd-complex}@ V> constexpr V exp(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V log(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V log10(const V& v); + + template<@\exposconcept{simd-complex}@ V> constexpr V sqrt(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V sin(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V asin(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V cos(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V acos(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V tan(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V atan(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V sinh(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V asinh(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V cosh(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V acosh(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V tanh(const V& v); + template<@\exposconcept{simd-complex}@ V> constexpr V atanh(const V& v); + + template<@\exposconcept{simd-floating-point}@ V> + rebind_t, V> polar(const V& x, const V& y = {}); + + template<@\exposconcept{simd-complex}@ V> constexpr V pow(const V& x, const V& y); +} + +namespace std { + // See \ref{simd.alg}, Algorithms + using datapar::min; + using datapar::max; + using datapar::minmax; + using datapar::clamp; + + // See \ref{simd.math}, Mathematical functions + using datapar::acos; + using datapar::asin; + using datapar::atan; + using datapar::atan2; + using datapar::cos; + using datapar::sin; + using datapar::tan; + using datapar::acosh; + using datapar::asinh; + using datapar::atanh; + using datapar::cosh; + using datapar::sinh; + using datapar::tanh; + using datapar::exp; + using datapar::exp2; + using datapar::expm1; + using datapar::frexp; + using datapar::ilogb; + using datapar::ldexp; + using datapar::log; + using datapar::log10; + using datapar::log1p; + using datapar::log2; + using datapar::logb; + using datapar::modf; + using datapar::scalbn; + using datapar::scalbln; + using datapar::cbrt; + using datapar::abs; + using datapar::abs; + using datapar::fabs; + using datapar::hypot; + using datapar::pow; + using datapar::sqrt; + using datapar::erf; + using datapar::erfc; + using datapar::lgamma; + using datapar::tgamma; + using datapar::ceil; + using datapar::floor; + using datapar::nearbyint; + using datapar::rint; + using datapar::lrint; + using datapar::llrint; + using datapar::round; + using datapar::lround; + using datapar::llround; + using datapar::trunc; + using datapar::fmod; + using datapar::remainder; + using datapar::remquo; + using datapar::copysign; + using datapar::nextafter; + using datapar::fdim; + using datapar::fmax; + using datapar::fmin; + using datapar::fma; + using datapar::lerp; + using datapar::fpclassify; + using datapar::isfinite; + using datapar::isinf; + using datapar::isnan; + using datapar::isnormal; + using datapar::signbit; + using datapar::isgreater; + using datapar::isgreaterequal; + using datapar::isless; + using datapar::islessequal; + using datapar::islessgreater; + using datapar::isunordered; + using datapar::assoc_laguerre; + using datapar::assoc_legendre; + using datapar::beta; + using datapar::comp_ellint_1; + using datapar::comp_ellint_2; + using datapar::comp_ellint_3; + using datapar::cyl_bessel_i; + using datapar::cyl_bessel_j; + using datapar::cyl_bessel_k; + using datapar::cyl_neumann; + using datapar::ellint_1; + using datapar::ellint_2; + using datapar::ellint_3; + using datapar::expint; + using datapar::hermite; + using datapar::laguerre; + using datapar::legendre; + using datapar::riemann_zeta; + using datapar::sph_bessel; + using datapar::sph_legendre; + using datapar::sph_neumann; + + // See \ref{simd.bit}, Bit manipulation + using datapar::byteswap; + using datapar::bit_ceil; + using datapar::bit_floor; + using datapar::has_single_bit; + using datapar::rotl; + using datapar::rotr; + using datapar::bit_width; + using datapar::countl_zero; + using datapar::countl_one; + using datapar::countr_zero; + using datapar::countr_one; + using datapar::popcount; + + // See \ref{simd.complex.math}, simd complex math + using datapar::real; + using datapar::imag; + using datapar::arg; + using datapar::norm; + using datapar::conj; + using datapar::proj; + using datapar::polar; +} +\end{codeblock} + +\rSec2[simd.traits]{\tcode{simd} type traits} + +\begin{itemdecl} +template struct alignment { @\seebelow@ }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{alignment} has a member \tcode{value} if and only if +\begin{itemize} + \item + \tcode{T} is a specialization of \tcode{basic_simd_mask} and \tcode{U} is + \tcode{bool}, or + \item + \tcode{T} is a specialization of \tcode{basic_simd} and \tcode{U} is a + vectorizable type. +\end{itemize} + +\pnum +If \tcode{value} is present, the type \tcode{alignment} is a +\tcode{BinaryTypeTrait} with a base characteristic of +\tcode{integral_constant} for some unspecified +\tcode{N}\iref{simd.ctor,simd.loadstore}. +\begin{note} +\tcode{value} identifies the alignment restrictions on pointers used for +(converting) loads and stores for the given type \tcode{T} on arrays of type +\tcode{U}. +\end{note} + +\pnum +The behavior of a program that adds specializations for \tcode{alignment} +is undefined. +\end{itemdescr} + +\begin{itemdecl} +template struct rebind { using type = @\seebelow@; }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The member \tcode{type} is present if and only if +\begin{itemize} +\item \tcode{V} is a data-parallel type, +\item \tcode{T} is a vectorizable type, and +\item \tcode{\exposid{deduce-abi-t}} has a member type + \tcode{type}. +\end{itemize} + +\pnum +If \tcode V is a specialization of \tcode{basic_simd}, let \tcode{Abi1} denote +an ABI tag such that \tcode{basic_simd::\brk{}size()} equals +\tcode{V::size()}. +If \tcode V is a specialization of \tcode{basic_simd_mask}, let \tcode{Abi1} +denote an ABI tag such that \tcode{basic_simd_mask::\brk{}size()} equals \tcode{V::size()}. + +\pnum +Where present, the member typedef \tcode{type} names \tcode{basic_simd} +if \tcode V is a specialization of \tcode{basic_simd} or +\tcode{basic_simd_mask} if \tcode V is a specialization of +\tcode{basic_simd_mask}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposid{simd-size-type}@ N, class V> struct resize { using type = @\seebelow@; }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{T} denote +\begin{itemize} + \item + \tcode{typename V::value_type} if \tcode{V} is a specialization of + \tcode{basic_simd}, + \item + otherwise \tcode{\exposid{integer-from}<\exposid{mask-element-size}>} if + \tcode{V} is a specialization of \tcode{basic_simd_mask}. +\end{itemize} + +\pnum +The member \tcode{type} is present if and only if +\begin{itemize} +\item \tcode{V} is a data-parallel type, and +\item \tcode{\exposid{deduce-abi-t}} has a member type \tcode{type}. +\end{itemize} + +\pnum +If \tcode V is a specialization of \tcode{basic_simd}, let \tcode{Abi1} denote an +ABI tag such that \tcode{basic_simd::\brk{}size()} equals +\tcode{V::size()}. +If \tcode V is a specialization of \tcode{basic_simd_mask}, let \tcode{Abi1} +denote an ABI tag such that \tcode{basic_simd_mask::\brk{}size()} equals \tcode{V::size()}. + +\pnum +Where present, the member typedef \tcode{type} names \tcode{basic_simd} +if \tcode V is a specialization of \tcode{basic_simd} or +\tcode{basic_simd_mask} if \tcode V is a specialization of +\tcode{basic_simd_mask}. +\end{itemdescr} + +\rSec2[simd.flags]{Load and store flags} + +\rSec3[simd.flags.overview]{Class template \tcode{flags} overview} + +\begin{codeblock} +namespace std::datapar { + template struct flags { + // \ref{simd.flags.oper}, \tcode{flags} operators + template + friend consteval auto operator|(flags, flags); + }; +} +\end{codeblock} + +\pnum +\begin{note} +The class template \tcode{flags} acts like an integer bit-flag for types. +\end{note} + +\pnum +\constraints +Every type in the parameter pack \tcode{Flags} is one of \tcode{\exposid{convert-flag}}, +\tcode{\exposid{aligned-flag}}, or \tcode{\exposid{over\-aligned-\brk{}flag}}. + +\rSec3[simd.flags.oper]{\tcode{flags} operators} + +\begin{itemdecl} +template + friend consteval auto operator|(flags a, flags b); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns + A default-initialized object of type \tcode{flags} for some + \tcode{Flags2} where every type in \tcode{Flags2} is present either in template parameter pack + \tcode{Flags} or in template parameter pack \tcode{Other}, and every type in template parameter + packs \tcode{Flags} and \tcode{Other} is present in \tcode{Flags2}. + If the packs \tcode{Flags} and \tcode{Other} contain two + different specializations \tcode{\exposid{overaligned-flag}} and + \tcode{\exposid{overaligned-flag}}, \tcode{Flags2} is not required to contain the + specialization \tcode{\exposid{overaligned-flag}}. +\end{itemdescr} + +\rSec2[simd.class]{Class template \tcode{basic_simd}} + +\rSec3[simd.overview]{Class template \tcode{basic_simd} overview} + +\begin{codeblock} +namespace std::datapar { + template class basic_simd { + public: + using value_type = T; + using mask_type = basic_simd_mask; + using abi_type = Abi; + + static constexpr integral_constant<@\exposid{simd-size-type}@, @\exposid{simd-size-v}@> size {}; + + constexpr basic_simd() noexcept = default; + + // \ref{simd.ctor}, \tcode{basic_simd} constructors + template constexpr explicit(@\seebelow@) basic_simd(U&& value) noexcept; + template + constexpr explicit(@\seebelow@) basic_simd(const basic_simd&) noexcept; + template constexpr explicit basic_simd(G&& gen) noexcept; + template + constexpr basic_simd(R&& range, flags = {}); + template + constexpr basic_simd(R&& range, const mask_type& mask, flags = {}); + template<@\exposconcept{simd-floating-point}@ V> + constexpr explicit(@\seebelow@) basic_simd(const V& reals, const V& imags = {}) noexcept; + + // \ref{simd.subscr}, \tcode{basic_simd} subscript operators + constexpr value_type operator[](@\exposid{simd-size-type}@) const; + + // \ref{simd.unary}, \tcode{basic_simd} unary operators + constexpr basic_simd& operator++() noexcept; + constexpr basic_simd operator++(int) noexcept; + constexpr basic_simd& operator--() noexcept; + constexpr basic_simd operator--(int) noexcept; + constexpr mask_type operator!() const noexcept; + constexpr basic_simd operator~() const noexcept; + constexpr basic_simd operator+() const noexcept; + constexpr basic_simd operator-() const noexcept; + + // \ref{simd.binary}, \tcode{basic_simd} binary operators + friend constexpr basic_simd operator+(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator-(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator*(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator/(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator%(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator&(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator|(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator^(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator<<(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator>>(const basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd operator<<(const basic_simd&, @\exposid{simd-size-type}@) noexcept; + friend constexpr basic_simd operator>>(const basic_simd&, @\exposid{simd-size-type}@) noexcept; + + // \ref{simd.cassign}, \tcode{basic_simd} compound assignment + friend constexpr basic_simd& operator+=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator-=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator*=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator/=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator%=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator&=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator|=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator^=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator<<=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator>>=(basic_simd&, const basic_simd&) noexcept; + friend constexpr basic_simd& operator<<=(basic_simd&, @\exposid{simd-size-type}@) noexcept; + friend constexpr basic_simd& operator>>=(basic_simd&, @\exposid{simd-size-type}@) noexcept; + + // \ref{simd.comparison}, \tcode{basic_simd} compare operators + friend constexpr mask_type operator==(const basic_simd&, const basic_simd&) noexcept; + friend constexpr mask_type operator!=(const basic_simd&, const basic_simd&) noexcept; + friend constexpr mask_type operator>=(const basic_simd&, const basic_simd&) noexcept; + friend constexpr mask_type operator<=(const basic_simd&, const basic_simd&) noexcept; + friend constexpr mask_type operator>(const basic_simd&, const basic_simd&) noexcept; + friend constexpr mask_type operator<(const basic_simd&, const basic_simd&) noexcept; + + // \ref{simd.complex.access}, \tcode{basic_simd} complex-value accessors + constexpr auto real() const noexcept; + constexpr auto imag() const noexcept; + template<@\exposconcept{simd-floating-point}@ V> + constexpr void real(const V& v) noexcept; + template<@\exposconcept{simd-floating-point}@ V> + constexpr void imag(const V& v) noexcept; + + // \ref{simd.cond}, \tcode{basic_simd} exposition only conditional operators + friend constexpr basic_simd @\exposid{simd-select-impl}@( // \expos + const mask_type&, const basic_simd&, const basic_simd&) noexcept; + }; + + template + basic_simd(R&& r, Ts...) -> @\seebelow@; +} +\end{codeblock} + +\pnum +Every specialization of \tcode{basic_simd} is a complete type. +The specialization of \tcode{basic_simd} is +\begin{itemize} + \item + enabled, if \tcode{T} is a vectorizable type, and there exists value + \tcode{N} in the range \crange{1}{64}, such that \tcode{Abi} is + \tcode{\exposid{deduce-abi-t}}, + \item + otherwise, disabled, if \tcode{T} is not a vectorizable type, + \item + otherwise, it is \impldef{set of enabled \tcode{basic_simd} + specializations} if such a specialization is enabled. +\end{itemize} + +If \tcode{basic_simd} is disabled, then the specialization has a +deleted default constructor, deleted destructor, deleted copy constructor, and +deleted copy assignment. +In addition only the \tcode{value_type}, \tcode{abi_type}, and +\tcode{mask_type} members are present. + +If \tcode{basic_simd} is enabled, then \tcode{basic_simd} is +trivially copyable, default-initialization of an object of such a type +default-initializes all elements, and value-initialization value-initializes +all elements\iref{dcl.init.general}. + +\pnum +\recommended +Implementations should support implicit conversions between specializations of +\tcode{basic_simd} and appropriate \impldef{conversions of \tcode{basic_simd} +from/to implementation-specific vector types} types. +\begin{note} +Appropriate types are non-standard vector types which are available in the +implementation. +\end{note} + +\rSec3[simd.ctor]{\tcode{basic_simd} constructors} + +\begin{itemdecl} +template constexpr explicit(@\seebelow@) basic_simd(U&& value) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{From} denote the type \tcode{remove_cvref_t}. + +\pnum +\constraints +\tcode{value_type} satisfies \tcode{\libconcept{constructible_from}}. + +\pnum +\effects +Initializes each element to the value of the argument after conversion to +\tcode{value_type}. + +\pnum +\remarks +The expression inside \tcode{explicit} evaluates to \tcode{false} if and only if +\tcode{U} satisfies \tcode{\libconcept{convertible_to}}, and either +\begin{itemize} + \item + \tcode{From} is not an arithmetic type and does not satisfy + \exposconcept{constexpr-wrapper-like}, + \item + \tcode{From} is an arithmetic type and the conversion from \tcode{From} to + \tcode{value_type} is value-preserving\iref{simd.general}, or + \item + \tcode{From} satisfies \exposconcept{constexpr-wrapper-like}, + \tcode{remove_const_t} is an arithmetic type, and + \tcode{From::value} is representable by \tcode{value_type}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr explicit(@\seebelow@) basic_simd(const basic_simd& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{\exposid{simd-size-v} == size()} is \tcode{true}. + +\pnum +\effects +Initializes the $i^\text{th}$ element with \tcode{static_cast(x[$i$])} for +all $i$ in the range of \range{0}{size()}. + +\pnum +\remarks +The expression inside \tcode{explicit} evaluates to \tcode{true} if either +\begin{itemize} + \item + the conversion from \tcode{U} to \tcode{value_type} is not value-preserving, + or + \item + both \tcode{U} and \tcode{value_type} are integral types and the integer + conversion rank\iref{conv.rank} of \tcode{U} is greater than the integer + conversion rank of \tcode{value_type}, or + \item + both \tcode{U} and \tcode{value_type} are floating-point types and the + floating-point conversion rank\iref{conv.rank} of \tcode{U} is greater than + the floating-point conversion rank of \tcode{value_type}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template constexpr explicit basic_simd(G&& gen); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{From}$_i$ denote the type +\tcode{decltype(gen(integral_constant<\exposid{simd-size-type}, $i$>()))}. + +\pnum +\constraints +\tcode{From}$_i$ satisfies \tcode{\libconcept{convertible_to}} for all $i$ in +the range of \range{0}{size()}. +In addition, for all $i$ in the range of \range{0}{size()}, if \tcode{From}$_i$ +is an arithmetic type, conversion from \tcode{From}$_i$ to \tcode{value_type} +is value-preserving. + +\pnum +\effects +Initializes the $i^\text{th}$ element with +\tcode{static_cast(gen(integral_constant<\exposid{simd-\brk{}size-\brk{}type}, +i>()))} for all $i$ in the range of \range{0}{size()}. + +\pnum +\remarks +\tcode{gen} is invoked exactly once for each $i$, in increasing order of $i$. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr basic_simd(R&& r, flags = {}); +template + constexpr basic_simd(R&& r, const mask_type& mask, flags = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{mask} be \tcode{mask_type(true)} for the overload with no +\tcode{mask} parameter. + +\pnum +\constraints +\begin{itemize} +\item \tcode{R} models \tcode{ranges::\libconcept{contiguous_range}} and + \tcode{ranges::\libconcept{sized_range}}, +\item \tcode{ranges::size(r)} is a constant expression, and +\item \tcode{ranges::size(r)} is equal to \tcode{size()}. +\end{itemize} + +\pnum +\mandates +\begin{itemize} + \item + \tcode{ranges::range_value_t} is a vectorizable type, and + \item + if the template parameter pack \tcode{Flags} does not contain + \tcode{\exposid{convert-flag}}, then the conversion from + \tcode{ranges::range_value_t} to \tcode{value_type} is value-preserving. +\end{itemize} + +\pnum +\expects +\begin{itemize} + \item + If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{aligned-flag}}, \tcode{ranges::data(r)} points to + storage aligned by \tcode{alignment_v>}. + \item + If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{overaligned-flag}}, \tcode{ranges::data(r)} points to + storage aligned by \tcode{N}. +\end{itemize} + +\pnum +\effects +Initializes the $i^\text{th}$ element with \tcode{mask[$i$] ? +static_cast(\brk{}ranges::\brk{}data(r)[$i$]) : T()} for all $i$ in the +range of \range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +template + basic_simd(R&& r, Ts...) -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{R} models \tcode{ranges::\libconcept{contiguous_range}} and + \tcode{ranges::\libconcept{sized_range}}, and +\item \tcode{ranges::size(r)} is a constant expression. +\end{itemize} + +\pnum +\remarks +The deduced type is equivalent to \tcode{simd, +ranges::size(r)>}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-floating-point}@ V> + constexpr explicit(@\seebelow@) + basic_simd(const V& reals, const V& imags = {}) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} + \item + \tcode{\exposconcept{simd-complex}} is modeled, and + \item + \tcode{V::size() == size()} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Initializes the $i^\text{th}$ element with \tcode{value_type(reals[$i$], +imags[$i$])} for all $i$ in the range \range{0}{size()}. + +\pnum +\remarks +The expression inside \tcode{explicit} evaluates to \tcode{false} if and only +if the floating-point conversion rank of \tcode{T::value_type} is greater than +or equal to the floating-point conversion rank of \tcode{V::value_type}. +\end{itemdescr} + +\rSec3[simd.subscr]{\tcode{basic_simd} subscript operator} + +\begin{itemdecl} +constexpr value_type operator[](@\exposid{simd-size-type}@ i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{i >= 0 \&\& i < size()} is \tcode{true}. + +\pnum +\returns +The value of the $i^\text{th}$ element. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\rSec3[simd.unary]{\tcode{basic_simd} unary operators} + +\pnum +Effects in [simd.unary] are applied as unary element-wise operations. + +\begin{itemdecl} +constexpr basic_simd& operator++() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (value_type a) \{ ++a; \}} is \tcode{true}. + +\pnum +\effects +Increments every element by one. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\begin{itemdecl} +constexpr basic_simd operator++(int) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (value_type a) \{ a++; \}} is \tcode{true}. + +\pnum +\effects +Increments every element by one. + +\pnum +\returns +A copy of \tcode{*this} before incrementing. +\end{itemdescr} + +\begin{itemdecl} +constexpr basic_simd& operator--() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (value_type a) \{ --a; \}} is \tcode{true}. + +\pnum +\effects +Decrements every element by one. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\begin{itemdecl} +constexpr basic_simd operator--(int) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (value_type a) \{ a--; \}} is \tcode{true}. + +\pnum +\effects +Decrements every element by one. + +\pnum +\returns +A copy of \tcode{*this} before decrementing. +\end{itemdescr} + +\begin{itemdecl} +constexpr mask_type operator!() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (const value_type a) \{ !a; \}} is \tcode{true}. + +\pnum +\returns +A \tcode{basic_simd_mask} object with the $i^\text{th}$ element set to +\tcode{!operator[]($i$)} for all $i$ in the range of \range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +constexpr basic_simd operator~() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (const value_type a) \{ \~{}a; \}} is \tcode{true}. + +\pnum +\returns +A \tcode{basic_simd} object with the $i^\text{th}$ element set to +\tcode{\~{}operator[]($i$)} for all $i$ in the range of \range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +constexpr basic_simd operator+() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (const value_type a) \{ +a; \}} is \tcode{true}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\begin{itemdecl} +constexpr basic_simd operator-() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{requires (const value_type a) \{ -a; \}} is \tcode{true}. + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +\tcode{-operator[]($i$)} for all $i$ in the range of \range{0}{size()}. +\end{itemdescr} + +\rSec2[simd.nonmembers]{\tcode{basic_simd} non-member operations} + +\rSec3[simd.binary]{\tcode{basic_simd} binary operators} + +\begin{itemdecl} +friend constexpr basic_simd operator+(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator-(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator*(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator/(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator%(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator&(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator|(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator^(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator<<(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd operator>>(const basic_simd& lhs, const basic_simd& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\constraints +\tcode{requires (value_type a, value_type b) \{ a \placeholder{op} b; \}} is +\tcode{true}. + +\pnum +\returns +A \tcode{basic_simd} object initialized with the results of applying +\placeholder{op} to \tcode{lhs} and \tcode{rhs} as a binary element-wise +operation. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr basic_simd operator<<(const basic_simd& v, @\exposid{simd-size-type}@ n) noexcept; +friend constexpr basic_simd operator>>(const basic_simd& v, @\exposid{simd-size-type}@ n) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\constraints +\tcode{requires (value_type a, \exposid{simd-size-type} b) \{ a +\placeholder{op} b; \}} is \tcode{true}. + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +the result of applying \placeholder{op} to \tcode{v[$i$]} and \tcode{n} for all +$i$ in the range of \range{0}{size()}. +\end{itemdescr} + +\rSec3[simd.cassign]{\tcode{basic_simd} compound assignment} + +\begin{itemdecl} +friend constexpr basic_simd& operator+=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator-=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator*=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator/=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator%=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator&=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator|=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator^=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator<<=(basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr basic_simd& operator>>=(basic_simd& lhs, const basic_simd& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\constraints +\tcode{requires (value_type a, value_type b) \{ a \placeholder{op} b; \}} is +\tcode{true}. + +\pnum +\effects +These operators apply the indicated operator to \tcode{lhs} and \tcode{rhs} as +an element-wise operation. + +\pnum +\returns +\tcode{lhs}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr basic_simd& operator<<=(basic_simd& lhs, @\exposid{simd-size-type}@ n) noexcept; +friend constexpr basic_simd& operator>>=(basic_simd& lhs, @\exposid{simd-size-type}@ n) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\constraints +\tcode{requires (value_type a, \exposid{simd-size-type} b) \{ a +\placeholder{op} b; \}} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return operator \placeholder{op} (lhs, basic_simd(n));} +\end{itemdescr} + +\rSec3[simd.comparison]{\tcode{basic_simd} compare operators} + +\begin{itemdecl} +friend constexpr mask_type operator==(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr mask_type operator!=(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr mask_type operator>=(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr mask_type operator<=(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr mask_type operator>(const basic_simd& lhs, const basic_simd& rhs) noexcept; +friend constexpr mask_type operator<(const basic_simd& lhs, const basic_simd& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\constraints +\tcode{requires (value_type a, value_type b) \{ a \placeholder{op} b; \}} is +\tcode{true}. + +\pnum +\returns +A \tcode{basic_simd_mask} object initialized with the results of applying +\placeholder{op} to \tcode{lhs} and \tcode{rhs} as a binary element-wise +operation. +\end{itemdescr} + +\rSec3[simd.complex.access]{\tcode{simd} complex accessors} + +\begin{itemdecl} +constexpr auto real() const noexcept; +constexpr auto imag() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{\exposconcept{simd-complex}} is modeled. + +\pnum +\returns +An object of type \tcode{rebind_t} +where the $i^\text{th}$ element is initialized to the result of +\tcode{\placeholder{cmplx-func}(operator[]($i$))} for all $i$ in the range +\range{0}{size()}, where \placeholder{cmplx-func} is the corresponding function +from \libheader{complex}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-floating-point}@ V> + constexpr void real(const V& v) noexcept; +template<@\exposconcept{simd-floating-point}@ V> + constexpr void imag(const V& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} + \item + \tcode{\exposconcept{simd-complex}} is modeled, + \item + \tcode{\libconcept{same_as}} + is modeled, and + \item + \tcode{V::size() == size()} is \tcode{true}. +\end{itemize} + +\pnum +\effects +Replaces each element of the \tcode{basic_simd} object such that the +$i^\text{th}$ element is replaced with \tcode{value_type(v[$i$], +operator[]($i$).imag())} or \tcode{value_type(operator[]($i$).real(), v[$i$])} +for \tcode{real} and \tcode{imag} respectively, for all $i$ in the range \range{0}{size()}. +\end{itemdescr} + +\rSec3[simd.cond]{\tcode{basic_simd} exposition only conditional operators} + +\begin{itemdecl} +friend constexpr basic_simd +@\exposid{simd-select-impl}@(const mask_type& mask, const basic_simd& a, const basic_simd& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element equals +\tcode{mask[$i$] ? a[$i$] : b[$i$]} for all $i$ in the range of +\range{0}{size()}. +\end{itemdescr} + +\rSec3[simd.reductions]{\tcode{basic_simd} reductions} + +\begin{itemdecl} +template> + constexpr T reduce(const basic_simd& x, BinaryOperation binary_op = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{BinaryOperation} models +\tcode{\exposconcept{reduction-binary-operation}}. + +\pnum +\expects +\tcode{binary_op} does not modify \tcode{x}. + +\pnum +\returns +\tcode{\placeholdernc{GENERALIZED_SUM}(binary_op, simd(x[0]), $\ldots$, +simd(x[x.size() - 1])\brk{})[0]}\iref{numerics.defns}. + +\pnum +\throws +Any exception thrown from \tcode{binary_op}. +\end{itemdescr} + +\begin{itemdecl} +template> + constexpr T reduce( + const basic_simd& x, const typename basic_simd::mask_type& mask, + BinaryOperation binary_op = {}, type_identity_t identity_element = @\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item + \tcode{BinaryOperation} models + \tcode{\exposconcept{reduction-binary-operation}}. +\item + An argument for \tcode{identity_element} is provided for the invocation, + unless \tcode{BinaryOperation} is one of \tcode{plus<>}, + \tcode{multiplies<>}, \tcode{bit_and<>}, \tcode{bit_or<>}, or + \tcode{bit_xor<>}. +\end{itemize} + +\pnum +\expects +\begin{itemize} + \item + \tcode{binary_op} does not modify \tcode{x}. + \item + For all finite values \tcode{y} representable by \tcode{T}, the results of + \tcode{y == binary_op(simd(iden\-ti\-ty\-_\-element), simd(y))[0]} and \tcode{y == binary_op(simd(y), simd(iden\-ti\-ty\-_\-element))[0]} are \tcode{true}. +\end{itemize} + +\pnum +\returns +If \tcode{none_of(mask)} is \tcode{true}, returns \tcode{identity_element}. +Otherwise, returns \tcode{\placeholdernc{GENERALIZED_SUM}(binary_op, simd(x[$k_0$]), $\ldots$, simd(x[$k_n$]))[0]} where $k_0, \ldots, k_n$ are +the selected indices of \tcode{mask}. + +\pnum +\throws +Any exception thrown from \tcode{binary_op}. + +\pnum +\remarks +The default argument for \tcode{identity_element} is equal to +\begin{itemize} +\item \tcode{T()} if \tcode{BinaryOperation} is \tcode{plus<>}, +\item \tcode{T(1)} if \tcode{BinaryOperation} is \tcode{multiplies<>}, +\item \tcode{T(\~{}T())} if \tcode{BinaryOperation} is \tcode{bit_and<>}, +\item \tcode{T()} if \tcode{BinaryOperation} is \tcode{bit_or<>}, or +\item \tcode{T()} if \tcode{BinaryOperation} is \tcode{bit_xor<>}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template constexpr T reduce_min(const basic_simd& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \tcode{totally_ordered}. + +\pnum +\returns +The value of an element \tcode{x[$j$]} for which \tcode{x[$i$] < x[$j$]} is +\tcode{false} for all $i$ in the range of \range{0}{basic_simd::size()}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr T reduce_min( + const basic_simd&, const typename basic_simd::mask_type&) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \tcode{totally_ordered}. + +\pnum +\returns +If \tcode{none_of(mask)} is \tcode{true}, returns +\tcode{numeric_limits::max()}. +Otherwise, returns the value of a selected element \tcode{x[$j$]} for which +\tcode{x[$i$] < x[$j$]} is \tcode{false} for all selected indices $i$ of +\tcode{mask}. +\end{itemdescr} + +\begin{itemdecl} +template constexpr T reduce_max(const basic_simd& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \tcode{totally_ordered}. + +\pnum +\returns +The value of an element \tcode{x[$j$]} for which \tcode{x[$j$] < x[$i$]} is +\tcode{false} for all $i$ in the range of \range{0}{basic_simd::size()}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr T reduce_max( + const basic_simd&, const typename basic_simd::mask_type&) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \tcode{totally_ordered}. + +\pnum +\returns +If \tcode{none_of(mask)} is \tcode{true}, returns +\tcode{numeric_limits::lowest()}. +Otherwise, returns the value of a selected element \tcode{x[$j$]} for which +\tcode{x[$j$] < x[$i$]} is \tcode{false} for all selected indices $i$ of +\tcode{mask}. +\end{itemdescr} + +\rSec3[simd.loadstore]{\tcode{basic_simd} load and store functions} + +\begin{itemdecl} +template + requires ranges::@\libconcept{sized_range}@ + constexpr V unchecked_load(R&& r, flags f = {}); +template + requires ranges::@\libconcept{sized_range}@ + constexpr V unchecked_load(R&& r, const typename V::mask_type& mask, flags f = {}); +template + constexpr V unchecked_load(I first, iter_difference_t n, flags f = {}); +template + constexpr V unchecked_load(I first, iter_difference_t n, const typename V::mask_type& mask, + flags f = {}); +template S, class... Flags> + constexpr V unchecked_load(I first, S last, flags f = {}); +template S, class... Flags> + constexpr V unchecked_load(I first, S last, const typename V::mask_type& mask, + flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let +\begin{itemize} + \item + \tcode{mask} be \tcode{V::mask_type(true)} for the overloads with no + \tcode{mask} parameter; + \item + \tcode{R} be \tcode{span>} for the overloads with no + template parameter \tcode{R}; + \item + \tcode{r} be \tcode{R(first, n)} for the overloads with an \tcode{n} + parameter and \tcode{R(first, last)} for the overloads with a \tcode{last} + parameter. +\end{itemize} + +\pnum +\mandates +If \tcode{ranges::size(r)} is a constant expression then +\tcode{ranges::size(r)} $\ge$ \tcode{V::size()}. + +\pnum +\expects +\begin{itemize} +\item \range{first}{first + n} is a valid range for the overloads with an + \tcode{n} parameter. +\item \range{first}{last} is a valid range for the overloads with a + \tcode{last} parameter. +\item \tcode{ranges::size(r)} $\ge$ \tcode{V::size()} +\end{itemize} + +\pnum +\effects +Equivalent to: \tcode{return partial_load(r, mask, f);} + +\pnum +\remarks +The default argument for template parameter \tcode{V} is +\tcode{basic_simd>}. +\end{itemdescr} + +\begin{itemdecl} +template + requires ranges::@\libconcept{sized_range}@ + constexpr V partial_load(R&& r, flags f = {}); +template + requires ranges::@\libconcept{sized_range}@ + constexpr V partial_load(R&& r, const typename V::mask_type& mask, flags f = {}); +template + constexpr V partial_load(I first, iter_difference_t n, flags f = {}); +template + constexpr V partial_load(I first, iter_difference_t n, const typename V::mask_type& mask, + flags f = {}); +template S, class... Flags> + constexpr V partial_load(I first, S last, flags f = {}); +template S, class... Flags> + constexpr V partial_load(I first, S last, const typename V::mask_type& mask, + flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let +\begin{itemize} + \item + \tcode{mask} be \tcode{V::mask_type(true)} for the overloads with no + \tcode{mask} parameter; + \item + \tcode{R} be \tcode{span>} for the overloads with no + template parameter \tcode{R}; + \item + \tcode{r} be \tcode{R(first, n)} for the overloads with an \tcode{n} + parameter and \tcode{R(first, last)} for the overloads with a \tcode{last} + parameter. +\end{itemize} + +\pnum +\mandates +\begin{itemize} + \item + \tcode{ranges::range_value_t} is a vectorizable type, + \item + \tcode{same_as, V>} is \tcode{true}, + \item + \tcode{V} is an enabled specialization of \tcode{basic_simd}, and + \item + if the template parameter pack \tcode{Flags} does not contain + \tcode{\exposid{convert-flag}}, then the conversion from + \tcode{ranges::range_value_t} to \tcode{V::value_type} is + value-preserving. +\end{itemize} + +\pnum +\expects +\begin{itemize} + \item + \range{first}{first + n} is a valid range for the overloads with an + \tcode{n} parameter. + \item + \range{first}{last} is a valid range for the overloads with a \tcode{last} + parameter. + \item + If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{aligned-flag}}, \tcode{ranges::data(r)} points to storage + aligned by \tcode{alignment_v>}. + \item + If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{overaligned-flag}}, \tcode{ranges::data(r)} points to + storage aligned by \tcode{N}. +\end{itemize} + +\pnum +\effects +Initializes the $i^\text{th}$ element with\\ +\tcode{mask[$i$] \&\& $i$ < ranges::size(r) ? +static_cast(\brk{}ranges::data(r)[$i$]) : T()} for all $i$ in the range of +\range{0}{V::size()}. + +\pnum +\remarks +The default argument for template parameter \tcode{V} is +\tcode{basic_simd>}. +\end{itemdescr} + +\begin{itemdecl} +template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void unchecked_store(const basic_simd& v, R&& r, flags f = {}); +template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void unchecked_store(const basic_simd& v, R&& r, + const typename basic_simd::mask_type& mask, flags f = {}); +template + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, iter_difference_t n, + flags f = {}); +template + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, iter_difference_t n, + const typename basic_simd::mask_type& mask, flags f = {}); +template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, S last, + flags f = {}); +template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void unchecked_store(const basic_simd& v, I first, S last, + const typename basic_simd::mask_type& mask, flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let +\begin{itemize} + \item + \tcode{mask} be \tcode{basic_simd::mask_type(true)} for the + overloads with no \tcode{mask} parameter; + \item + \tcode{R} be \tcode{span>} for the overloads with no + template parameter \tcode{R}; + \item + \tcode{r} be \tcode{R(first, n)} for the overloads with an \tcode{n} + parameter and \tcode{R(first, last)} for the overloads with a \tcode{last} + parameter. +\end{itemize} + +\pnum +\mandates +If \tcode{ranges::size(r)} is a constant expression then +\tcode{ranges::size(r)} $\ge$ \tcode{\exposid{simd-size-v}}. + +\pnum +\expects +\begin{itemize} + \item + \range{first}{first + n} is a valid range for the overloads with an + \tcode{n} parameter. + \item + \range{first}{last} is a valid range for the overloads with a \tcode{last} + parameter. + \item + \tcode{ranges::size(r)} $\ge$ \tcode{\exposid{simd-size-v}} +\end{itemize} + +\pnum +\effects +Equivalent to: \tcode{partial_store(v, r, mask, f)}. +\end{itemdescr} + +\begin{itemdecl} +template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void partial_store(const basic_simd& v, R&& r, flags f = {}); +template + requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + constexpr void partial_store(const basic_simd& v, R&& r, + const typename basic_simd::mask_type& mask, flags f = {}); +template + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store(const basic_simd& v, I first, iter_difference_t n, + flags f = {}); +template + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store(const basic_simd& v, I first, iter_difference_t n, + const typename basic_simd::mask_type& mask, flags f = {}); +template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store(const basic_simd& v, I first, S last, + flags f = {}); +template S, class... Flags> + requires @\libconcept{indirectly_writable}@ + constexpr void partial_store(const basic_simd& v, I first, S last, + const typename basic_simd::mask_type& mask, flags f = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let +\begin{itemize} + \item + \tcode{mask} be \tcode{basic_simd::mask_type(true)} for the + overloads with no \tcode{mask} parameter; + \item + \tcode{R} be \tcode{span>} for the overloads with no + template parameter \tcode{R}; + \item + \tcode{r} be \tcode{R(first, n)} for the overloads with an \tcode{n} + parameter and \tcode{R(first, last)} for the overloads with a \tcode{last} + parameter. +\end{itemize} + +\pnum +\mandates +\begin{itemize} + \item + \tcode{ranges::range_value_t} is a vectorizable type, and + \item + if the template parameter pack \tcode{Flags} does not contain + \tcode{\exposid{convert-flag}}, then the conversion from \tcode{T} to + \tcode{ranges::range_value_t} is value-preserving. +\end{itemize} + +\pnum +\expects +\begin{itemize} + \item + \range{first}{first + n} is a valid range for the overloads with an + \tcode{n} parameter. + \item + \range{first}{last} is a valid range for the overloads with a \tcode{last} + parameter. + \item + If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{aligned-flag}}, \tcode{ranges::data(r)} points to storage + aligned by \tcode{alignment_v, + ranges::range_value_t>}. + \item + If the template parameter pack \tcode{Flags} contains + \tcode{\exposid{overaligned-flag}}, \tcode{ranges::data(r)} points to + storage aligned by \tcode{N}. +\end{itemize} + +\pnum +\effects +For all $i$ in the range of \range{0}{basic_simd::size()}, if +\tcode{mask[$i$] \&\& $i$ < ranges::\brk{}size(r)} is \tcode{true}, evaluates +\tcode{ranges::data(r)[$i$] = v[$i$]}. +\end{itemdescr} + +\rSec3[simd.creation]{\tcode{basic_simd} and \tcode{basic_simd_mask} creation} + +\begin{itemdecl} +template + constexpr auto chunk(const basic_simd& x) noexcept; +template + constexpr auto chunk(const basic_simd_mask<@\exposid{mask-element-size}@, Abi>& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} + \item + For the first overload \tcode{T} is an enabled specialization of + \tcode{basic_simd}. + If \tcode{basic_simd<\brk{}typename T::\brk{}value_type, Abi>::size() \% + T::size()} is not \tcode{0} then + \tcode{resize_t::size() + \% T::size(), T>} is valid and denotes a type. + + \item + For the second overload \tcode{T} is an enabled specialization of + \tcode{basic_simd\-_\-mask}. + If \tcode{basic_simd_mask<\exposid{mask-element-size}, Abi>::size() \% + T::size()} is not \tcode{0} then + \tcode{resize_t<\brk{}ba\-sic\-_\-simd_mask<\brk{}\exposid{mask-element-size}, + Abi>::size() \% T::size(), T>} is valid and denotes a type. +\end{itemize} + +\pnum +Let $N$ be \tcode{x.size() / T::size()}. + +\pnum +\returns +\begin{itemize} + \item + If \tcode{x.size() \% T::size() == 0} is \tcode{true}, an \tcode{array} with the $i^\text{th}$ \tcode{basic_simd} or \tcode{basic_simd_mask} + element of the $j^\text{th}$ \tcode{array} element initialized to the value + of the element in \tcode{x} with index \tcode{$i$ + $j$ * T::size()}. + + \item + Otherwise, a \tcode{tuple} of $N$ objects of type \tcode{T} and one object + of type \tcode{resize_t}. + The $i^\text{th}$ \tcode{basic_simd} or \tcode{basic_simd_mask} element of + the $j^\text{th}$ \tcode{tuple} element of type \tcode{T} is initialized to + the value of the element in \tcode{x} with index \tcode{$i$ + $j$ * + T::size()}. + The $i^\text{th}$ \tcode{basic_simd} or \tcode{basic_simd_mask} element of + the $N^\text{th}$ \tcode{tuple} element is initialized to the value of the + element in \tcode{x} with index \tcode{$i$ + $N$ * T::size()}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr auto chunk(const basic_simd& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return chunk>>(x);} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr auto chunk(const basic_simd_mask& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return chunk>>(x);} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr simd::size() + ...)> + cat(const basic_simd&... xs) noexcept; +template + constexpr basic_simd_mask, + (basic_simd_mask::size() + ...)>> + cat(const basic_simd_mask&... xs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} + \item + For the first overload \tcode{simd::size() + ...)>} + is enabled. + \item + For the second overload + \tcode{basic_simd_mask, + (ba\-sic_simd_mask::size() + ...)>>} is enabled. +\end{itemize} + +\pnum +\returns +A data-parallel object initialized with the concatenated values in the +\tcode{xs} pack of data-parallel objects: The $i^\text{th}$ +\tcode{basic_simd}/\tcode{basic_simd_mask} element of the $j^\text{th}$ +parameter in the \tcode{xs} pack is copied to the return value's element with +index $i$ + the sum of the width of the first $j$ parameters in the \tcode{xs} +pack. +\end{itemdescr} + +\rSec3[simd.alg]{Algorithms} + +\begin{itemdecl} +template + constexpr basic_simd min(const basic_simd& a, + const basic_simd& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \tcode{totally_ordered}. + +\pnum +\returns +The result of the element-wise application of \tcode{min(a[$i$], b[$i$])} for +all $i$ in the range of \range{0}{basic_simd::size()}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr basic_simd max(const basic_simd& a, + const basic_simd& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \tcode{totally_ordered}. + +\pnum +\returns +The result of the element-wise application of \tcode{max(a[$i$], b[$i$])} for +all $i$ in the range of \range{0}{basic_simd::size()}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr pair, basic_simd> + minmax(const basic_simd& a, const basic_simd& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return pair\{min(a, b), max(a, b)\};} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr basic_simd clamp( + const basic_simd& v, const basic_simd& lo, const basic_simd& hi); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \tcode{totally_ordered}. + +\pnum +\expects +No element in \tcode{lo} shall be greater than the corresponding element in +\tcode{hi}. + +\pnum +\returns +The result of element-wise application of \tcode{clamp(v[$i$], lo[$i$], +hi[$i$])} for all $i$ in the range of \range{0}{basic_simd::size()}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr auto select(bool c, const T& a, const U& b) + -> remove_cvref_t; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return c ? a : b;} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr auto select(const basic_simd_mask& c, const T& a, const U& b) + noexcept -> decltype(@\exposid{simd-select-impl}@(c, a, b)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{simd-select-impl}@(c, a, b); +\end{codeblock} +where \tcode{\exposid{simd-select-impl}} is found by argument-dependent +lookup\iref{basic.lookup.argdep} contrary to \ref{contents}. +\end{itemdescr} + +\rSec3[simd.math]{Mathematical functions} + +\begin{itemdecl} +template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> ilogb(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ ldexp(const V& x, const rebind_t>& exp); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ scalbn(const V& x, const rebind_t>& n); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ + scalbln(const V& x, const rebind_t>& n); +template<@\libconcept{signed_integral}@ T, class Abi> + constexpr basic_simd abs(const basic_simd& j); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ abs(const V& j); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ fabs(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ ceil(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ floor(const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ nearbyint(const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ rint(const V& x); +template<@\exposconcept{math-floating-point}@ V> + rebind_t> lrint(const V& x); +template<@\exposconcept{math-floating-point}@ V> + rebind_t> llrint(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ round(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> lround(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> llround(const V& x); +template + constexpr @\exposid{math-common-simd-t}@ fmod(const V0& x, const V1& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ trunc(const V& x); +template + constexpr @\exposid{math-common-simd-t}@ remainder(const V0& x, const V1& y); +template + constexpr @\exposid{math-common-simd-t}@ copysign(const V0& x, const V1& y); +template + constexpr @\exposid{math-common-simd-t}@ nextafter(const V0& x, const V1& y); +template + constexpr @\exposid{math-common-simd-t}@ fdim(const V0& x, const V1& y); +template + constexpr @\exposid{math-common-simd-t}@ fmax(const V0& x, const V1& y); +template + constexpr @\exposid{math-common-simd-t}@ fmin(const V0& x, const V1& y); +template + constexpr @\exposid{math-common-simd-t}@ fma(const V0& x, const V1& y, const V2& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr rebind_t> fpclassify(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isfinite(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isinf(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isnan(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type isnormal(const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-simd-t}@::mask_type signbit(const V& x); +template + constexpr typename @\exposid{math-common-simd-t}@::mask_type isgreater(const V0& x, const V1& y); +template + constexpr typename @\exposid{math-common-simd-t}@::mask_type + isgreaterequal(const V0& x, const V1& y); +template + constexpr typename @\exposid{math-common-simd-t}@::mask_type isless(const V0& x, const V1& y); +template + constexpr typename @\exposid{math-common-simd-t}@::mask_type islessequal(const V0& x, const V1& y); +template + constexpr typename @\exposid{math-common-simd-t}@::mask_type islessgreater(const V0& x, const V1& y); +template + constexpr typename @\exposid{math-common-simd-t}@::mask_type isunordered(const V0& x, const V1& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{Ret} denote the return type of the specialization of a function +template with the name \placeholder{math-func}. +Let \placeholder{math-func-simd} denote: +\begin{codeblock} +template +Ret @\placeholder{math-func-simd}@(Args... args) { + return Ret([&](@\exposid{simd-size-type}@ i) { + @\placeholder{math-func}@(@\exposid{make-compatible-simd-t}@(args)[i]...); + }); +} +\end{codeblock} + +\pnum +\returns +A value \tcode{ret} of type \tcode{Ret}, that is element-wise equal to the +result of calling \placeholder{math-func-simd} with the arguments of the above +functions. +If in an invocation of a scalar overload of \placeholder{math-func} for index +\tcode{i} in \placeholder{math-func-simd} a domain, pole, or range error would +occur, the value of \tcode{ret[i]} is unspecified. + +\pnum +\remarks +It is unspecified whether \tcode{errno}\iref{errno} is accessed. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ acos(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ asin(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ atan(const V& x); +template + constexpr @\exposid{math-common-simd-t}@ atan2(const V0& y, const V1& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ cos(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ sin(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ tan(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ acosh(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ asinh(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ atanh(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ cosh(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ sinh(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ tanh(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ exp(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ exp2(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ expm1(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log10(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log1p(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ log2(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ logb(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ cbrt(const V& x); +template + constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y); +template + constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y, const V2& z); +template + constexpr @\exposid{math-common-simd-t}@ pow(const V0& x, const V1& y); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ sqrt(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ erf(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ erfc(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ lgamma(const V& x); +template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-simd-t}@ tgamma(const V& x); +template + constexpr @\exposid{math-common-simd-t}@ lerp(const V0& a, const V1& b, const V2& t) noexcept; +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ assoc_laguerre(const rebind_t>& n, const + rebind_t>& m, + const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ assoc_legendre(const rebind_t>& l, const + rebind_t>& m, + const V& x); +template + @\exposid{math-common-simd-t}@ beta(const V0& x, const V1& y); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ comp_ellint_1(const V& k); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ comp_ellint_2(const V& k); +template + @\exposid{math-common-simd-t}@ comp_ellint_3(const V0& k, const V1& nu); +template + @\exposid{math-common-simd-t}@ cyl_bessel_i(const V0& nu, const V1& x); +template + @\exposid{math-common-simd-t}@ cyl_bessel_j(const V0& nu, const V1& x); +template + @\exposid{math-common-simd-t}@ cyl_bessel_k(const V0& nu, const V1& x); +template + @\exposid{math-common-simd-t}@ cyl_neumann(const V0& nu, const V1& x); +template + @\exposid{math-common-simd-t}@ ellint_1(const V0& k, const V1& phi); +template + @\exposid{math-common-simd-t}@ ellint_2(const V0& k, const V1& phi); +template + @\exposid{math-common-simd-t}@ ellint_3(const V0& k, const V1& nu, const V2& phi); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ expint(const V& x); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ hermite(const rebind_t>& n, const V& x); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ laguerre(const rebind_t>& n, const V& x); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ legendre(const rebind_t>& l, const V& x); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ riemann_zeta(const V& x); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ sph_bessel(const rebind_t>& n, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-simd-t}@ sph_legendre(const rebind_t>& l, + const rebind_t>& m, + const V& theta); +template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-simd-t}@ sph_neumann(const rebind_t>& n, const V& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{Ret} denote the return type of the specialization of a function +template with the name \placeholder{math-func}. +Let \placeholder{math-func-simd} denote: +\begin{codeblock} +template +Ret @\placeholder{math-func-simd}@(Args... args) { + return Ret([&](@\exposid{simd-size-type}@ i) { + @\placeholder{math-func}@(@\exposid{make-compatible-simd-t}@(args)[i]...); + }); +} +\end{codeblock} + +\pnum +\returns +A value \tcode{ret} of type \tcode{Ret}, that is element-wise approximately +equal to the result of calling \placeholder{math-func-simd} with the arguments +of the above functions. +If in an invocation of a scalar overload of \placeholder{math-func} for index +\tcode{i} in \placeholder{math-func-simd} a domain, pole, or range error would +occur, the value of \tcode{ret[i]} is unspecified. + +\pnum +\remarks +It is unspecified whether \tcode{errno}\iref{errno} is accessed. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-simd-t}@ frexp(const V& value, rebind_t>* exp); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{Ret} be \tcode{\exposid{deduced-simd-t}}. +Let \placeholder{frexp-simd} denote: +\begin{codeblock} +template +pair> @\placeholder{frexp-simd}@(const V& x) { + int r1[Ret::size()]; + Ret r0([&](@\exposid{simd-size-type}@ i) { + frexp(@\exposid{make-compatible-simd-t}@(x)[i], &r1[i]); + }); + return {r0, rebind_t(r1)}; +} +\end{codeblock} +Let \tcode{ret} be a value of type \tcode{pair>} +that is the same value as the result of calling +\placeholder{frexp-simd}\tcode{(x)}. + +\pnum +\effects +Sets \tcode{*exp} to \tcode{ret.second}. + +\pnum +\returns +\tcode{ret.first}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr @\exposid{math-common-simd-t}@ remquo(const V0& x, const V1& y, + rebind_t>* quo); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{Ret} be \tcode{\exposid{math-common-simd-t}}. +Let \placeholder{remquo-simd} denote: +\begin{codeblock} +template +pair> @\placeholder{remquo-simd}@(const V0& x, const V1& y) { + int r1[Ret::size()]; + Ret r0([&](@\exposid{simd-size-type}@ i) { + remquo(@\exposid{make-compatible-simd-t}@(x)[i], + @\exposid{make-compatible-simd-t}@(y)[i], &r1[i]); + }); + return {r0, rebind_t(r1)}; +} +\end{codeblock} +Let \tcode{ret} be a value of type \tcode{pair>} +that is the same value as the result of calling +\placeholder{remquo-simd}\tcode{(x, y)}. +If in an invocation of a scalar overload of \tcode{remquo} for index \tcode{i} +in \placeholder{remquo-simd} a domain, pole, or range error would occur, the +value of \tcode{ret[i]} is unspecified. + +\pnum +\effects +Sets \tcode{*quo} to \tcode{ret.second}. + +\pnum +\returns +\tcode{ret.first}. + +\pnum +\remarks +It is unspecified whether \tcode{errno}\iref{errno} is accessed. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr basic_simd modf(const type_identity_t>& value, + basic_simd* iptr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{V} be \tcode{basic_simd}. +Let \placeholder{modf-simd} denote: +\begin{codeblock} +pair @\placeholder{modf-simd}@(const V& x) { + T r1[Ret::size()]; + V r0([&](@\exposid{simd-size-type}@ i) { + modf(V(x)[i], &r1[i]); + }); + return {r0, V(r1)}; +} +\end{codeblock} +Let \tcode{ret} be a value of type \tcode{pair} that is the same value as +the result of calling \placeholder{modf-simd}\tcode{(value)}. + +\pnum +\effects +Sets \tcode{*iptr} to \tcode{ret.second}. + +\pnum +\returns +\tcode{ret.first}. +\end{itemdescr} + +\rSec3[simd.bit]{\tcode{basic_simd} bit library} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> constexpr V byteswap(const V& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The type \tcode{V::value_type} models \tcode{integral}. + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +the result of \tcode{std::byteswap(v[$i$])} for all $i$ in the range +\range{0}{V::size()}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> constexpr V bit_ceil(const V& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The type \tcode{V::value_type} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\expects +For every $i$ in the range \range{0}{V::size()}, the smallest power of 2 +greater than or equal to \tcode{v[$i$]} is representable as a value of type +\tcode{V::value_type}. + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +the result of \tcode{std::bit_ceil(v[$i$])} for all $i$ in the range +\range{0}{V::size()}. + +\pnum +\remarks +A function call expression that violates the precondition in the \expects +element is not a core constant expression\iref{expr.const}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> constexpr V bit_floor(const V& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The type \tcode{V::value_type} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +the result of \tcode{std::bit_floor(v[$i$])} for all $i$ in the range +\range{0}{V::size()}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> + constexpr typename V::mask_type has_single_bit(const V& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The type \tcode{V::value_type} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +A \tcode{basic_simd_mask} object where the $i^\text{th}$ element is initialized +to the result of \tcode{std::has_single_bit(v[$i$])} for all $i$ in the range +\range{0}{V::size()}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V0, @\exposconcept{simd-type}@ V1> + constexpr V0 rotl(const V0& v0, const V1& v1) noexcept; +template<@\exposconcept{simd-type}@ V0, @\exposconcept{simd-type}@ V1> + constexpr V0 rotr(const V0& v0, const V1& v1) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} + \item + The type \tcode{V0::value_type} is an unsigned integer type\iref{basic.fundamental}, + \item + the type \tcode{V1::value_type} models \tcode{integral}, + \item + \tcode{V0::size() == V1::size()} is \tcode{true}, and + \item + \tcode{sizeof(typename V0::value_type) == sizeof(typename V1::value_type)} is \tcode{true}. +\end{itemize} + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +the result of \tcode{\placeholder{bit-func}(v0[$i$], +static_cast(v1[$i$]))} for all $i$ in the range \range{0}{V0::size()}, +where \placeholder{bit-func} is the corresponding scalar function from \libheader{bit}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> constexpr V rotl(const V& v, int s) noexcept; +template<@\exposconcept{simd-type}@ V> constexpr V rotr(const V& v, int s) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The type \tcode{V::value_type} is an unsigned integer type\iref{basic.fundamental} + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +the result of \tcode{\placeholder{bit-func}(v[$i$], s)} for all $i$ in the +range \range{0}{V::size()}, where \placeholder{bit-func} is the corresponding +scalar function from \libheader{bit}. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> bit_width(const V& v) noexcept; +template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> countl_zero(const V& v) noexcept; +template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> countl_one(const V& v) noexcept; +template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> countr_zero(const V& v) noexcept; +template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> countr_one(const V& v) noexcept; +template<@\exposconcept{simd-type}@ V> + constexpr rebind_t, V> popcount(const V& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The type \tcode{V::value_type} is an unsigned integer type\iref{basic.fundamental} + +\pnum +\returns +A \tcode{basic_simd} object where the $i^\text{th}$ element is initialized to +the result of \tcode{\placeholder{bit-func}(v[$i$])} for all $i$ in the range +\range{0}{V::size()}, where \placeholder{bit-func} is the corresponding scalar +function from \libheader{bit}. +\end{itemdescr} + +\rSec3[simd.complex.math]{\tcode{simd} complex math} + +\begin{itemdecl} +template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> real(const V&) noexcept; +template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> imag(const V&) noexcept; + +template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> abs(const V&); +template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> arg(const V&); +template<@\exposconcept{simd-complex}@ V> + constexpr rebind_t<@\exposid{simd-complex-value-type}@, V> norm(const V&); +template<@\exposconcept{simd-complex}@ V> constexpr V conj(const V&); +template<@\exposconcept{simd-complex}@ V> constexpr V proj(const V&); + +template<@\exposconcept{simd-complex}@ V> constexpr V exp(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V log(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V log10(const V& v); + +template<@\exposconcept{simd-complex}@ V> constexpr V sqrt(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V sin(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V asin(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V cos(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V acos(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V tan(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V atan(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V sinh(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V asinh(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V cosh(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V acosh(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V tanh(const V& v); +template<@\exposconcept{simd-complex}@ V> constexpr V atanh(const V& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{basic_simd} object \tcode{ret} where the $i^\text{th}$ element is +initialized to the result of \tcode{\placeholder{cmplx-func}(v[$i$])} for all +$i$ in the range \range{0}{V::size()}, where \placeholder{cmplx-func} is the +corresponding function from \libheader{complex}. If in an invocation of +\placeholder{cmplx-func} for index $i$ a domain, pole, or range error would +occur, the value of \tcode{ret[$i$]} is unspecified. + +\pnum +\remarks +It is unspecified whether \tcode{errno}\iref{errno} is accessed. +\end{itemdescr} + +\begin{itemdecl} +template<@\exposconcept{simd-floating-point}@ V> + rebind_t, V> polar(const V& x, const V& y = {}); + +template<@\exposconcept{simd-complex}@ V> constexpr V pow(const V& x, const V& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{basic_simd} object \tcode{ret} where the $i^\text{th}$ element is +initialized to the result of \tcode{\placeholder{cmplx-func}(x[$i$], y[$i$])} +for all $i$ in the range \range{0}{V::size()}, where \placeholder{cmplx-func} +is the corresponding function from \libheader{complex}. If in an invocation of +\placeholder{cmplx-func} for index $i$ a domain, pole, or range error would +occur, the value of \tcode{ret[$i$]} is unspecified. + +\pnum +\remarks +It is unspecified whether \tcode{errno}\iref{errno} is accessed. +\end{itemdescr} + +\rSec2[simd.mask.class]{Class template \tcode{basic_simd_mask}} + +\rSec3[simd.mask.overview]{Class template \tcode{basic_simd_mask} overview} + +\begin{codeblock} +namespace std::datapar { + template class basic_simd_mask { + public: + using value_type = bool; + using abi_type = Abi; + + static constexpr integral_constant<@\exposid{simd-size-type}@, @\exposid{simd-size-v}@<@\exposid{integer-from}@, Abi>> + size {}; + + constexpr basic_simd_mask() noexcept = default; + + // \ref{simd.mask.ctor}, \tcode{basic_simd_mask} constructors + constexpr explicit basic_simd_mask(value_type) noexcept; + template + constexpr explicit basic_simd_mask(const basic_simd_mask&) noexcept; + template constexpr explicit basic_simd_mask(G&& gen) noexcept; + + // \ref{simd.mask.subscr}, \tcode{basic_simd_mask} subscript operators + constexpr value_type operator[](@\exposid{simd-size-type}@) const; + + // \ref{simd.mask.unary}, \tcode{basic_simd_mask} unary operators + constexpr basic_simd_mask operator!() const noexcept; + constexpr basic_simd<@\exposid{integer-from}@, Abi> operator+() const noexcept; + constexpr basic_simd<@\exposid{integer-from}@, Abi> operator-() const noexcept; + constexpr basic_simd<@\exposid{integer-from}@, Abi> operator~() const noexcept; + + // \ref{simd.mask.conv}, \tcode{basic_simd_mask} conversion operators + template + constexpr explicit(sizeof(U) != Bytes) operator basic_simd() const noexcept; + + // \ref{simd.mask.binary}, \tcode{basic_simd_mask} binary operators + friend constexpr basic_simd_mask + operator&&(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator||(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator&(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator|(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator^(const basic_simd_mask&, const basic_simd_mask&) noexcept; + + // \ref{simd.mask.cassign}, \tcode{basic_simd_mask} compound assignment + friend constexpr basic_simd_mask& + operator&=(basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask& + operator|=(basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask& + operator^=(basic_simd_mask&, const basic_simd_mask&) noexcept; + + // \ref{simd.mask.comparison}, \tcode{basic_simd_mask} comparisons + friend constexpr basic_simd_mask + operator==(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator!=(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator>=(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator<=(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator>(const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask + operator<(const basic_simd_mask&, const basic_simd_mask&) noexcept; + + // \ref{simd.mask.cond}, \tcode{basic_simd_mask} exposition only conditional operators + friend constexpr basic_simd_mask @\exposid{simd-select-impl}@( // \expos + const basic_simd_mask&, const basic_simd_mask&, const basic_simd_mask&) noexcept; + friend constexpr basic_simd_mask @\exposid{simd-select-impl}@( // \expos + const basic_simd_mask&, @\libconcept{same_as}@ auto, @\libconcept{same_as}@ auto) noexcept; + template + friend constexpr simd<@\seebelow@, size()> + @\exposid{simd-select-impl}@(const basic_simd_mask&, const T0&, const T1&) noexcept; // \expos + }; +} +\end{codeblock} + +\pnum +Every specialization of \tcode{basic_simd_mask} is a complete type. +The specialization of \tcode{basic_simd_mask} is: +\begin{itemize} + \item + disabled, if there is no vectorizable type \tcode{T} such that \tcode{Bytes} + is equal to \tcode{sizeof(T)}, + \item + otherwise, enabled, if there exists a vectorizable type \tcode{T} and a + value \tcode{N} in the range \crange{1}{64} such that \tcode{Bytes} is equal + to \tcode{sizeof(T)} and \tcode{Abi} is \tcode{\exposid{deduce-abi-t}}, + \item + otherwise, it is \impldef{set of enabled \tcode{basic_simd_mask} + specializations} if such a specialization is enabled. +\end{itemize} + +If \tcode{basic_simd_mask} is disabled, the specialization has a +deleted default constructor, deleted destructor, deleted copy constructor, and +deleted copy assignment. +In addition only the \tcode{value_type} and \tcode{abi_type} members are +present. + +If \tcode{basic_simd_mask} is enabled, +\tcode{basic_simd_mask} is trivially copyable. + +\pnum +\recommended Implementations should support implicit conversions between +specializations of \tcode{basic_simd_mask} and appropriate \impldef{conversions +of \tcode{basic_simd_mask} from/to implementation-specific vector types} types. +\begin{note} +Appropriate types are non-standard vector types which are available in the +implementation. +\end{note} + +\rSec3[simd.mask.ctor]{\tcode{basic_simd_mask} constructors} + +\begin{itemdecl} +constexpr explicit basic_simd_mask(value_type x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes each element with \tcode{x}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr explicit basic_simd_mask(const basic_simd_mask& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{basic_simd_mask::size() == size()} is +\tcode{true}. + +\pnum +\effects +Initializes the $i^\text{th}$ element with \tcode{x[$i$]} for all $i$ in the +range of \range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +template constexpr explicit basic_simd_mask(G&& gen); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The expression \tcode{gen(integral_constant<\exposid{simd-size-type}, i>())} is +well-formed and its type is \tcode{bool} for all $i$ in the range of +\range{0}{size()}. + +\pnum +\effects +Initializes the $i^\text{th}$ element with +\tcode{gen(integral_constant<\exposid{simd-size-type}, i>())} for all $i$ in +the range of \range{0}{size()}. + +\pnum +\remarks +\tcode{gen} is invoked exactly once for each $i$, in increasing order of $i$. +\end{itemdescr} + +\rSec3[simd.mask.subscr]{\tcode{basic_simd_mask} subscript operator} + +\begin{itemdecl} +constexpr value_type operator[](@\exposid{simd-size-type}@ i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{i >= 0 \&\& i < size()} is \tcode{true}. + +\pnum +\returns +The value of the $i^\text{th}$ element. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\rSec3[simd.mask.unary]{\tcode{basic_simd_mask} unary operators} + +\begin{itemdecl} +constexpr basic_simd_mask operator!() const noexcept; +constexpr basic_simd<@\exposid{integer-from}@, Abi> operator+() const noexcept; +constexpr basic_simd<@\exposid{integer-from}@, Abi> operator-() const noexcept; +constexpr basic_simd<@\exposid{integer-from}@, Abi> operator~() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\returns +A data-parallel object where the $i^\text{th}$ element is initialized to the +results of applying \placeholder{op} to \tcode{operator[]($i$)} for all $i$ in +the range of \range{0}{size()}. +\end{itemdescr} + +\rSec3[simd.mask.conv]{\tcode{basic_simd_mask} conversion operators} + +\begin{itemdecl} +template + constexpr explicit(sizeof(U) != Bytes) operator basic_simd() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{\exposid{simd-size-v} == \exposid{simd-size-v}}. + +\pnum +\returns +A data-parallel object where the $i^\text{th}$ element is initialized to +\tcode{static_cast(operator[]($i$))}. +\end{itemdescr} + +\rSec2[simd.mask.nonmembers]{Non-member operations} + +\rSec3[simd.mask.binary]{\tcode{basic_simd_mask} binary operators} + +\begin{itemdecl} +friend constexpr basic_simd_mask + operator&&(const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +friend constexpr basic_simd_mask + operator||(const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +friend constexpr basic_simd_mask + operator& (const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +friend constexpr basic_simd_mask + operator| (const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +friend constexpr basic_simd_mask + operator^ (const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\returns +A \tcode{basic_simd_mask} object initialized with the results of applying +\placeholder{op} to \tcode{lhs} and \tcode{rhs} as a binary element-wise +operation. +\end{itemdescr} + +\rSec3[simd.mask.cassign]{\tcode{basic_simd_mask} compound assignment} + +\begin{itemdecl} +friend constexpr basic_simd_mask& + operator&=(basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +friend constexpr basic_simd_mask& + operator|=(basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +friend constexpr basic_simd_mask& + operator^=(basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\effects +These operators apply \placeholder{op} to \tcode{lhs} and \tcode{rhs} as a +binary element-wise operation. + +\pnum +\returns +\tcode{lhs}. +\end{itemdescr} + +\rSec3[simd.mask.comparison]{\tcode{basic_simd_mask} comparisons} + +\begin{itemdecl} +friend constexpr basic_simd_mask + operator==(const basic_simd_mask&, const basic_simd_mask&) noexcept; +friend constexpr basic_simd_mask + operator!=(const basic_simd_mask&, const basic_simd_mask&) noexcept; +friend constexpr basic_simd_mask + operator>=(const basic_simd_mask&, const basic_simd_mask&) noexcept; +friend constexpr basic_simd_mask + operator<=(const basic_simd_mask&, const basic_simd_mask&) noexcept; +friend constexpr basic_simd_mask + operator>(const basic_simd_mask&, const basic_simd_mask&) noexcept; +friend constexpr basic_simd_mask + operator<(const basic_simd_mask&, const basic_simd_mask&) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + +\pnum +\returns +A \tcode{basic_simd_mask} object initialized with the results of applying +\placeholder{op} to \tcode{lhs} and \tcode{rhs} as a binary element-wise +operation. +\end{itemdescr} + +\rSec3[simd.mask.cond]{\tcode{basic_simd_mask} exposition only conditional operators} + +\begin{itemdecl} +friend constexpr basic_simd_mask @\exposid{simd-select-impl}@( + const basic_simd_mask& mask, const basic_simd_mask& a, const basic_simd_mask& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{basic_simd_mask} object where the $i^\text{th}$ element equals +\tcode{mask[$i$] ? a[$i$] : b[$i$]} for all $i$ in the range of +\range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr basic_simd_mask +@\exposid{simd-select-impl}@(const basic_simd_mask& mask, @\libconcept{same_as}@ auto a, @\libconcept{same_as}@ auto b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{basic_simd_mask} object where the $i^\text{th}$ element equals +\tcode{mask[$i$] ? a : b} for all $i$ in the range of \range{0}{size()}. +\end{itemdescr} + +\begin{itemdecl} +template + friend constexpr simd<@\seebelow@, size()> + @\exposid{simd-select-impl}@(const basic_simd_mask& mask, const T0& a, const T1& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} + \item + \tcode{same_as} is \tcode{true}, + \item + \tcode{T0} is a vectorizable type, and + \item + \tcode{sizeof(T0) == Bytes}. +\end{itemize} + +\pnum +\returns +A \tcode{simd} object where the $i^\text{th}$ element equals +\tcode{mask[$i$] ? a : b} for all $i$ in the range of \range{0}{size()}. +\end{itemdescr} + +\rSec3[simd.mask.reductions]{\tcode{basic_simd_mask} reductions} + +\begin{itemdecl} +template + constexpr bool all_of(const basic_simd_mask& k) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if all boolean elements in \tcode{k} are \tcode{true}, otherwise +\tcode{false}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr bool any_of(const basic_simd_mask& k) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if at least one boolean element in \tcode{k} is \tcode{true}, +otherwise \tcode{false}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr bool none_of(const basic_simd_mask& k) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!any_of(k)}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr @\exposid{simd-size-type}@ reduce_count(const basic_simd_mask& k) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The number of boolean elements in \tcode{k} that are \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr @\exposid{simd-size-type}@ reduce_min_index(const basic_simd_mask& k); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{any_of(k)} is \tcode{true}. + +\pnum +\returns +The lowest element index $i$ where \tcode{k[$i$]} is \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +template + constexpr @\exposid{simd-size-type}@ reduce_max_index(const basic_simd_mask& k); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{any_of(k)} is \tcode{true}. + +\pnum +\returns +The greatest element index $i$ where \tcode{k[$i$]} is \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +constexpr bool all_of(@\libconcept{same_as}@ auto x) noexcept; +constexpr bool any_of(@\libconcept{same_as}@ auto x) noexcept; +constexpr @\exposid{simd-size-type}@ reduce_count(@\libconcept{same_as}@ auto x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x}. +\end{itemdescr} + +\begin{itemdecl} +constexpr bool none_of(@\libconcept{same_as}@ auto x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!x}. +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{simd-size-type}@ reduce_min_index(@\libconcept{same_as}@ auto x); +constexpr @\exposid{simd-size-type}@ reduce_max_index(@\libconcept{same_as}@ auto x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{x} is \tcode{true}. + +\pnum +\returns +\tcode{0}. +\end{itemdescr} + +\rSec1[numerics.c]{C compatibility} + +\rSec2[stdckdint.h.syn]{Header \tcode{} synopsis} + +\indexheader{stdckdint.h}% +\begin{codeblock} +#define @\libmacro{__STDC_VERSION_STDCKDINT_H__}@ 202311L + +template + bool ckd_add(type1* result, type2 a, type3 b); +template + bool ckd_sub(type1* result, type2 a, type3 b); +template + bool ckd_mul(type1* result, type2 a, type3 b); +\end{codeblock} + +\pnum +\xref{\IsoCUndated{}:2024, 7.20} %% TODO: change to \xrefc{7.20} + +\rSec2[numerics.c.ckdint]{Checked integer operations} + +\indexlibraryglobal{ckd_add}% +\indexlibraryglobal{ckd_sub}% +\indexlibraryglobal{ckd_mul}% +\begin{itemdecl} +template + bool ckd_add(type1* result, type2 a, type3 b); +template + bool ckd_sub(type1* result, type2 a, type3 b); +template + bool ckd_mul(type1* result, type2 a, type3 b); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +Each of the types \tcode{type1}, \tcode{type2}, and \tcode{type3} is a +cv-unqualified signed or unsigned integer type. + +\pnum +\remarks +Each function template has the same semantics as +the corresponding type-generic macro with the same name +specified in \IsoCUndated{}:2024, 7.20. +\end{itemdescr} diff --git a/source/overloading.tex b/source/overloading.tex index f357452fa6..5343a015a7 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -185,7 +185,7 @@ \end{itemize} where \tcode{X} -is the class of which the function is a member and +is the class of which the function is a direct member and \cv{} is the cv-qualification on the member function declaration. @@ -464,11 +464,28 @@ argument as in a qualified function call. If the current class is, or is derived from, \tcode{T}, and the keyword \keyword{this}\iref{expr.prim.this} refers to it, -then the implied object argument is \tcode{(*this)}. +\begin{itemize} +\item +if the unqualified function call +appears in a precondition assertion of a constructor +or a postcondition assertion of a destructor +and overload resolution selects a non-static member function, +the call is ill-formed; +\item +otherwise, +the implied object argument is +\tcode{(*\keyword{this})}. +\end{itemize} Otherwise, +\begin{itemize} +\item +if overload resolution selects a non-static member function, +the call is ill-formed; +\item +otherwise, a contrived object of type \tcode{T} -becomes the implied object argument; +becomes the implied object argument. \begin{footnote} An implied object argument is contrived to correspond to the implicit object @@ -482,12 +499,12 @@ reject a function. \end{footnote} -if overload resolution selects a non-static member function, -the call is ill-formed. +\end{itemize} + \begin{example} \begin{codeblock} struct C { - void a(); + bool a(); void b() { a(); // OK, \tcode{(*this).a()} } @@ -524,6 +541,15 @@ void m(this const C& c) { c.k(); // OK } + + C() + pre(a()) // error: implied \keyword{this} in constructor precondition + pre(this->a()) // OK + post(a()); // OK + ~C() + pre(a()) // OK + post(a()) // error: implied \keyword{this} in destructor postcondition + post(this->a()); // OK }; \end{codeblock} \end{example} @@ -676,7 +702,7 @@ \hdstyle{Subclause} & \hdstyle{Expression} & \hdstyle{As member function} & \hdstyle{As non-member function} \\ \capsep \ref{over.unary} & \tcode{@a} & \tcode{(a).\keyword{operator}@ (\,)} & \tcode{\keyword{operator}@(a)} \\ \ref{over.binary} & \tcode{a@b} & \tcode{(a).\keyword{operator}@ (b)} & \tcode{\keyword{operator}@(a, b)} \\ -\ref{over.ass} & \tcode{a=b} & \tcode{(a).\keyword{operator}= (b)} & \\ +\ref{over.assign} & \tcode{a=b} & \tcode{(a).\keyword{operator}= (b)} & \\ \ref{over.sub} & \tcode{a[b]} & \tcode{(a).\keyword{operator}[](b)} & \\ \ref{over.ref} & \tcode{a->} & \tcode{(a).\keyword{operator}->(\,)} & \\ \ref{over.inc} & \tcode{a@} & \tcode{(a).\keyword{operator}@ (0)} & \tcode{\keyword{operator}@(a, 0)} \\ @@ -1001,17 +1027,18 @@ or default-initialized\iref{dcl.init}, overload resolution selects the constructor. For direct-initialization or default-initialization -that is not in the context of copy-initialization, the -candidate functions are +(including default-initialization in the context of copy-list-initialization), +the candidate functions are all the constructors of the class of the object being initialized. -For copy-initialization (including default initialization -in the context of copy-initialization), the candidate functions are all -the converting constructors\iref{class.conv.ctor} of that +Otherwise, the candidate functions are all +the non-explicit constructors\iref{class.conv.ctor} of that class. The argument list is the \grammarterm{expression-list} or \grammarterm{assignment-expression} of the \grammarterm{initializer}. +For default-initialization in the context of copy-list-initialization, +if an explicit constructor is chosen, the initialization is ill-formed. \rSec3[over.match.copy]{Copy-initialization of class by user-defined conversion}% \indextext{overloading!resolution!initialization} @@ -1036,7 +1063,7 @@ \begin{itemize} \item -The converting constructors\iref{class.conv.ctor} of +The non-explicit constructors\iref{class.conv.ctor} of \tcode{T} are candidate functions. \item @@ -1117,11 +1144,11 @@ \begin{itemize} \item ``lvalue reference to \cvqual{cv2} \tcode{T2}'' -(when initializing an lvalue reference or an rvalue reference to function) and +(when converting to an lvalue) and \item ``\cvqual{cv2} \tcode{T2}'' -and ``rvalue reference to \cvqual{cv2} \tcode{T2}'' (when initializing an -rvalue reference or an lvalue reference to function) +and ``rvalue reference to \cvqual{cv2} \tcode{T2}'' +(when converting to an rvalue or an lvalue of function type) \end{itemize} for any \tcode{T2}. The permissible types for non-explicit conversion functions are @@ -1172,7 +1199,7 @@ chosen, the initialization is ill-formed. \begin{note} This differs from other situations\iref{over.match.ctor,over.match.copy}, -where only converting constructors are considered for copy-initialization. +where only non-explicit constructors are considered for copy-initialization. This restriction only applies if this initialization is part of the final result of overload resolution. @@ -1198,7 +1225,18 @@ by the template parameters (including default template arguments) of the constructor, if any. \item -The types of the function parameters are those of the constructor. +The associated constraints\iref{temp.constr.decl} are the conjunction of +the associated constraints of \tcode{C} and +the associated constraints of the constructor, if any. +\begin{note} +A \grammarterm{constraint-expression} in +the \grammarterm{template-head} of \tcode{C} +is checked for satisfaction before any constraints from +the \grammarterm{template-head} or trailing \grammarterm{requires-clause} +of the constructor. +\end{note} +\item +The \grammarterm{parameter-declaration-clause} is that of the constructor. \item The return type is the class template specialization designated by \tcode{C} @@ -1224,8 +1262,8 @@ \begin{itemize} \item -The template parameters, if any, -and function parameters +The \grammarterm{template-head}, if any, +and \grammarterm{parameter-declaration-clause} are those of the \grammarterm{deduction-guide}. \item The return type @@ -1722,10 +1760,10 @@ (see~\ref{dcl.init}, \ref{over.match.conv}, and~\ref{over.match.ref}) and the standard conversion sequence -from the return type of $\tcode{F}_1$ to the destination type +from the result of $\tcode{F}_1$ to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence -from the return type of $\tcode{F}_2$ to the destination type +from the result of $\tcode{F}_2$ to the destination type \begin{example} \begin{codeblock} struct A { @@ -1743,8 +1781,8 @@ \item the context is an initialization by conversion function for direct reference binding\iref{over.match.ref} of a reference to function type, the -return type of \tcode{F1} is the same kind of reference (lvalue or rvalue) -as the reference being initialized, and the return type of \tcode{F2} is not +return type of $\tcode{F}_1$ is the same kind of reference (lvalue or rvalue) +as the reference being initialized, and the return type of $\tcode{F}_2$ is not \begin{example} \begin{codeblock} template struct A { @@ -1760,38 +1798,52 @@ or, if not that, \item -\tcode{F1} +$\tcode{F}_1$ is not a function template specialization and -\tcode{F2} +$\tcode{F}_2$ is a function template specialization, or, if not that, \item -\tcode{F1} +$\tcode{F}_1$ and -\tcode{F2} +$\tcode{F}_2$ are function template specializations, and the function template for -\tcode{F1} +$\tcode{F}_1$ is more specialized than the template for -\tcode{F2} +$\tcode{F}_2$ according to the partial ordering rules described in~\ref{temp.func.order}, or, if not that, \item -\tcode{F1} and \tcode{F2} are non-template functions with the same -parameter-type-lists, and \tcode{F1} is more constrained than \tcode{F2} -according to the partial ordering of constraints described in -\ref{temp.constr.order}, or if not that, +$\tcode{F}_1$ and $\tcode{F}_2$ are non-template functions and +$\tcode{F}_1$ is more partial-ordering-constrained than +$\tcode{F}_2$\iref{temp.constr.order} +\begin{example} +\begin{codeblock} +template +struct S { + constexpr void f(); // \#1 + constexpr void f(this S&) requires true; // \#2 +}; + +void test() { + S<> s; + s.f(); // calls \#2 +} +\end{codeblock} +\end{example} +or, if not that, \item -\tcode{F1} is a constructor for a class \tcode{D}, -\tcode{F2} is a constructor for a base class \tcode{B} of \tcode{D}, and +$\tcode{F}_1$ is a constructor for a class \tcode{D}, +$\tcode{F}_2$ is a constructor for a base class \tcode{B} of \tcode{D}, and for all arguments -the corresponding parameters of \tcode{F1} and \tcode{F2} have the same type +the corresponding parameters of $\tcode{F}_1$ and $\tcode{F}_2$ have the same type \begin{example} \begin{codeblock} struct A { @@ -1811,8 +1863,8 @@ or, if not that, \item -\tcode{F2} is a rewritten candidate\iref{over.match.oper} and -\tcode{F1} is not +$\tcode{F}_2$ is a rewritten candidate\iref{over.match.oper} and +$\tcode{F}_1$ is not \begin{example} \begin{codeblock} struct S { @@ -1825,10 +1877,10 @@ or, if not that, \item -\tcode{F1} and \tcode{F2} are rewritten candidates, and -\tcode{F2} is a synthesized candidate +$\tcode{F}_1$ and $\tcode{F}_2$ are rewritten candidates, and +$\tcode{F}_2$ is a synthesized candidate with reversed order of parameters -and \tcode{F1} is not +and $\tcode{F}_1$ is not \begin{example} \begin{codeblock} struct S { @@ -1838,32 +1890,32 @@ bool b = 1 < S(); // calls \#2 \end{codeblock} \end{example} -or, if not that +or, if not that, \item -\tcode{F1} and \tcode{F2} are generated +$\tcode{F}_1$ and $\tcode{F}_2$ are generated from class template argument deduction\iref{over.match.class.deduct} for a class \tcode{D}, and -\tcode{F2} is generated +$\tcode{F}_2$ is generated from inheriting constructors from a base class of \tcode{D} -while \tcode{F1} is not, and +while $\tcode{F}_1$ is not, and for each explicit function argument, -the corresponding parameters of \tcode{F1} and \tcode{F2} +the corresponding parameters of $\tcode{F}_1$ and $\tcode{F}_2$ are either both ellipses or have the same type, or, if not that, \item -\tcode{F1} is generated from a +$\tcode{F}_1$ is generated from a \grammarterm{deduction-guide}\iref{over.match.class.deduct} -and \tcode{F2} is not, or, if not that, +and $\tcode{F}_2$ is not, or, if not that, \item -\tcode{F1} is the copy deduction candidate\iref{over.match.class.deduct} -and \tcode{F2} is not, or, if not that, +$\tcode{F}_1$ is the copy deduction candidate\iref{over.match.class.deduct} +and $\tcode{F}_2$ is not, or, if not that, \item -\tcode{F1} is generated from a non-template constructor -and \tcode{F2} is generated from a constructor template. +$\tcode{F}_1$ is generated from a non-template constructor +and $\tcode{F}_2$ is generated from a constructor template. \begin{example} \begin{codeblock} template struct A { @@ -2112,8 +2164,8 @@ or when converting to the left operand of an assignment operation only standard conversion sequences are allowed. \begin{note} -When converting to the explicit object parameter, if any, -user-defined conversion sequences are allowed. +When a conversion to the explicit object parameter occurs, +it can include user-defined conversion sequences. \end{note} \pnum @@ -2259,7 +2311,7 @@ \pnum If the user-defined conversion is specified by a specialization of a conversion function template, -the second standard conversion sequence shall have exact match rank. +the second standard conversion sequence shall have Exact Match rank. \pnum A conversion of an expression of class type @@ -2281,11 +2333,32 @@ \rSec4[over.ics.ref]{Reference binding} \pnum -When a parameter of reference type binds directly\iref{dcl.init.ref} to an -argument expression, the implicit conversion sequence is the identity conversion, -unless the argument expression has a type that is a derived class of the parameter -type, in which case the implicit conversion sequence is a derived-to-base +When a parameter of type ``reference to \cv~\tcode{T}'' +binds directly\iref{dcl.init.ref} to an argument expression: +\begin{itemize} +\item +If the argument expression has a type that +is a derived class of the parameter type, +the implicit conversion sequence is a derived-to-base conversion\iref{over.best.ics}. + +\item +Otherwise, +if the type of the argument is possibly cv-qualified \tcode{T}, or +if \tcode{T} is an array type of unknown bound with element type \tcode{U} and +the argument has an array type of known bound whose +element type is possibly cv-qualified \tcode{U}, +the implicit conversion sequence is the identity conversion. + +\item +Otherwise, +if \tcode{T} is a function type, +the implicit conversion sequence is a function pointer conversion. + +\item +Otherwise, the implicit conversion sequence is a qualification conversion. +\end{itemize} + \begin{example} \begin{codeblock} struct A {}; @@ -2293,14 +2366,18 @@ int f(A&); int f(B&); int i = f(b); // calls \tcode{f(B\&)}, an exact match, rather than \tcode{f(A\&)}, a conversion + +void g() noexcept; +int h(void (&)() noexcept); // \#1 +int h(void (&)()); // \#2 +int j = h(g); // calls \#1, an exact match, rather than \#2, a function pointer conversion \end{codeblock} \end{example} If the parameter binds directly to the result of applying a conversion function to the argument expression, the implicit conversion sequence is a user-defined conversion sequence\iref{over.ics.user} -whose second standard conversion sequence is either an identity conversion or, -if the conversion function returns an entity of a type that is a derived class -of the parameter type, a derived-to-base conversion. +whose second standard conversion sequence is +determined by the above rules. \pnum When a parameter of reference type is not bound directly to an argument @@ -2318,7 +2395,7 @@ binding an lvalue reference other than a reference to a non-volatile \keyword{const} type to an rvalue -or binding an rvalue reference to an lvalue other than a function lvalue. +or binding an rvalue reference to an lvalue of object type. \begin{note} This means, for example, that a candidate function cannot be a viable function if it has a non-\keyword{const} lvalue reference parameter (other than @@ -2716,8 +2793,8 @@ \item \tcode{S1} and \tcode{S2} include reference bindings\iref{dcl.init.ref} and -\tcode{S1} binds an lvalue reference to a function lvalue and \tcode{S2} binds -an rvalue reference to a function lvalue +\tcode{S1} binds an lvalue reference to an lvalue of function type and +\tcode{S2} binds an rvalue reference to an lvalue of function type \begin{example} \begin{codeblock} int f(void(&)()); // \#1 @@ -2731,28 +2808,33 @@ \item \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. +yield similar types \tcode{T1} and \tcode{T2}, respectively +(where a standard conversion sequence that is a reference binding +is considered to yield the cv-unqualified referenced type), +where \tcode{T1} and \tcode{T2} are not the same type, and +\tcode{const T2} is reference-compatible with \tcode{T1}\iref{dcl.init.ref} \begin{example} \begin{codeblock} int f(const volatile int *); int f(const int *); int i; int j = f(&i); // calls \tcode{f(const int*)} +int g(const int*); +int g(const volatile int* const&); +int* p; +int k = g(p); // calls \tcode{g(const int*)} \end{codeblock} \end{example} or, if not that, + \item \tcode{S1} and \tcode{S2} -include reference bindings\iref{dcl.init.ref}, and the types to which the references -refer are the same type except for top-level cv-qualifiers, and the type to -which the reference initialized by -\tcode{S2} -refers is more cv-qualified than the type to which the reference initialized by -\tcode{S1} -refers. +bind ``reference to \tcode{T1}'' and ``reference to \tcode{T2}'', +respectively\iref{dcl.init.ref}, +where \tcode{T1} and \tcode{T2} are not the same type, and +\tcode{T2} is reference-compatible with \tcode{T1} \begin{example} \begin{codeblock} int f(const int &); @@ -2772,6 +2854,39 @@ a.f(); // calls \tcode{X::f() const} b.f(); // calls \tcode{X::f()} } + +int h(int (&)[]); +int h(int (&)[1]); +void g2() { + int a[1]; + h(a); // calls \tcode{h(int (\&)[1])} +} +\end{codeblock} +\end{example} +or, if not that, + +\item +\tcode{S1} and \tcode{S2} +bind the same reference type ``reference to \tcode{T}'' and +have source types \tcode{V1} and \tcode{V2}, respectively, +where the standard conversion sequence from \tcode{V1*} to \tcode{T*} +is better than the standard conversion sequence from \tcode{V2*} to \tcode{T*}. +\begin{example} +\begin{codeblock} +struct Z {}; + +struct A { + operator Z&(); + operator const Z&(); // \#1 +}; + +struct B { + operator Z(); + operator const Z&&(); // \#2 +}; + +const Z& r1 = A(); // OK, uses \#1 +const Z&& r2 = B(); // OK, uses \#2 \end{codeblock} \end{example} \end{itemize} @@ -3004,7 +3119,7 @@ \item an object or reference being initialized\iref{dcl.init,dcl.init.ref,dcl.init.list}, \item -the left side of an assignment\iref{expr.ass}, +the left side of an assignment\iref{expr.assign}, \item a parameter of a function\iref{expr.call}, \item @@ -3014,9 +3129,11 @@ \item an explicit type conversion\iref{expr.type.conv,expr.static.cast,expr.cast}, or \item -a non-type -\grammarterm{template-parameter}\iref{temp.arg.nontype}. +a constant template parameter\iref{temp.arg.nontype}. \end{itemize} +If the target type contains a placeholder type, +placeholder type deduction is performed\iref{dcl.type.auto.deduct}, and +the remainder of this subclause uses the target type so deduced. The \grammarterm{id-expression} can be preceded by the \tcode{\&} operator. \begin{note} Any redundant set of parentheses surrounding the function name is @@ -3069,10 +3186,8 @@ \tcode{F0} is eliminated if the set contains a second non-template function that -is more constrained than -\tcode{F0} -according to -the partial ordering rules of \ref{temp.constr.order}. +is more partial-ordering-constrained than +\tcode{F0}\iref{temp.constr.order}. Any given function template specialization \tcode{F1} @@ -3108,8 +3223,9 @@ with type \tcode{int(...)} has been declared, and not because of any ambiguity. -For another example, +\end{example} +\begin{example} \begin{codeblock} struct X { int f(int); @@ -3126,6 +3242,21 @@ \end{codeblock} \end{example} +\begin{example} +\begin{codeblock} +template struct X { + void f(short) requires B; + void f(long); + template void g(short) requires B; + template void g(long); +}; +void test() { + &X::f; // error: ambiguous; constraints are not considered + &X::g; // error: ambiguous; constraints are not considered +} +\end{codeblock} +\end{example} + \pnum \begin{note} If \tcode{f} and \tcode{g} are both overload sets, @@ -3176,13 +3307,13 @@ \begin{bnf} %% Ed. note: character protrusion would misalign various operators. -\microtypesetup{protrusion=false}\obeyspaces +\microtypesetup{protrusion=false} \nontermdef{operator} \textnormal{one of}\br - \terminal{new delete new[] delete[] co_await (\rlap{\,)} [\rlap{\,]} -> ->*}\br - \terminal{\~ ! + - * / \% \caret{} \&}\br - \terminal{| = += -= *= /= \%= \caret{}= \&=}\br - \terminal{|= == != < > <= >= <=> \&\&}\br - \terminal{|| << >> <<= >>= ++ -- ,}\br + \terminal{new \ \ \ \ \ delete \ \ new[] \ \ \ delete[] co_await (\rlap{\,)} \ \ \ \ \ \ \ [\rlap{\,]} \ \ \ \ \ \ \ -> \ \ \ \ \ \ ->*}\br + \terminal{\~ \ \ \ \ \ \ \ ! \ \ \ \ \ \ \ + \ \ \ \ \ \ \ - \ \ \ \ \ \ \ * \ \ \ \ \ \ \ / \ \ \ \ \ \ \ \% \ \ \ \ \ \ \ \caret{} \ \ \ \ \ \ \ \&}\br + \terminal{| \ \ \ \ \ \ \ = \ \ \ \ \ \ \ += \ \ \ \ \ \ -= \ \ \ \ \ \ *= \ \ \ \ \ \ /= \ \ \ \ \ \ \%= \ \ \ \ \ \ \caret{}= \ \ \ \ \ \ \&=}\br + \terminal{|= \ \ \ \ \ \ == \ \ \ \ \ \ != \ \ \ \ \ \ < \ \ \ \ \ \ \ > \ \ \ \ \ \ \ <= \ \ \ \ \ \ >= \ \ \ \ \ \ <=> \ \ \ \ \ \&\&}\br + \terminal{|| \ \ \ \ \ \ << \ \ \ \ \ \ >> \ \ \ \ \ \ <<= \ \ \ \ \ >>= \ \ \ \ \ ++ \ \ \ \ \ \ -- \ \ \ \ \ \ ,}\br \end{bnf} \begin{note} The operators @@ -3200,8 +3331,8 @@ \pnum Both the unary and binary forms of -\begin{ncsimplebnf}\obeyspaces -\terminal{+ - * \&} +\begin{ncsimplebnf} +\terminal{+ \ \ \ \ \ - \ \ \ \ \ * \ \ \ \ \ \&} \end{ncsimplebnf} can be overloaded. @@ -3209,8 +3340,8 @@ \begin{note} \indextext{restriction!operator overloading}% The following operators cannot be overloaded: -\begin{ncsimplebnf}\obeyspaces -\terminal{. .* :: ?:} +\begin{ncsimplebnf} +\terminal{. \ \ \ \ \ .* \ \ \ \ :: \ \ \ \ ?:} \end{ncsimplebnf} nor can the preprocessing symbols \tcode{\#}\iref{cpp.stringize} @@ -3252,15 +3383,10 @@ \pnum \indextext{restriction!overloading}% An operator function -shall either -\begin{itemize} -\item -be a member function or -\item -be a non-member function that -has at least one non-object parameter whose type is a class, a reference to a class, an +shall have at least one +function parameter or implicit object parameter whose type is +a class, a reference to a class, an enumeration, or a reference to an enumeration. -\end{itemize} It is not possible to change the precedence, grouping, or number of operands of operators. The meaning of @@ -3281,14 +3407,14 @@ \pnum \indextext{operator}% \begin{note} -The identities among certain predefined operators applied to basic types +The identities among certain predefined operators applied to fundamental types (for example, \tcode{++a} $\equiv$ \tcode{a+=1}) need not hold for operator functions. Some predefined operators, such as \tcode{+=}, -require an operand to be an lvalue when applied to basic types; +require an operand to be an lvalue when applied to fundamental types; this is not required by operator functions. \end{note} @@ -3302,7 +3428,7 @@ described in the rest of \ref{over.oper}. \pnum -Operators not mentioned explicitly in subclauses~\ref{over.ass} through~\ref{over.inc} +Operators not mentioned explicitly in subclauses~\ref{over.assign} through~\ref{over.inc} act as ordinary unary and binary operators obeying the rules of~\ref{over.unary} or~\ref{over.binary}.% \indextext{overloading!resolution!best viable function|)}% @@ -3383,7 +3509,7 @@ a relational operator function, or a three-way comparison operator function. -\rSec3[over.ass]{Simple assignment} +\rSec3[over.assign]{Simple assignment} \indextext{assignment operator!overloaded}% \indextext{overloading!assignment operator} @@ -3994,12 +4120,13 @@ A \defnx{numeric literal operator template}{literal!operator!template numeric} is a literal operator template whose \grammarterm{template-parameter-list} has a single \grammarterm{template-parameter} -that is a non-type template parameter pack\iref{temp.variadic} +that is a constant template parameter pack\iref{temp.variadic} with element type \tcode{char}. A \defnx{string literal operator template}{literal!operator!template string} is a literal operator template whose \grammarterm{template-parameter-list} comprises -a single non-type \grammarterm{template-parameter} of class type. +a single \grammarterm{parameter-declaration} that declares a +constant template parameter of class type. The declaration of a literal operator template shall have an empty \grammarterm{parameter-declaration-clause} and shall declare either a numeric literal operator template diff --git a/source/preface.tex b/source/preface.tex index 1e11dd524f..6e0b3fa036 100644 --- a/source/preface.tex +++ b/source/preface.tex @@ -1,4 +1,19 @@ %!TEX root = std.tex + \chapter{Foreword} [This page is intentionally left blank.] + +\chapter{Introduction} + +Clauses and subclauses in this document are annotated +with a so-called stable name, +presented in square brackets next to the (sub)clause heading +(such as ``[lex.token]'' for \ref{lex.token}, ``Tokens''). +Stable names aid in the discussion and evolution of this document +by serving as stable references to subclauses across editions +that are unaffected by changes of subclause numbering. + +Aspects of the language syntax of \Cpp{} are distinguished typographically +by the use of \fakegrammarterm{italic, sans-serif} type +or \tcode{constant width} type to avoid ambiguities; see \ref{syntax}. diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 1d32a61af0..ee7959abeb 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -45,17 +45,18 @@ \terminal{\#} conditionally-supported-directive \end{bnf} -\begin{bnf}\obeyspaces +\begin{bnf} \nontermdef{control-line}\br \terminal{\# include} pp-tokens new-line\br pp-import\br + \terminal{\# embed \ } 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 \terminal{\# define } identifier lparen identifier-list \terminal{, ... )} replacement-list new-line\br - \terminal{\# undef } identifier new-line\br - \terminal{\# line } pp-tokens new-line\br - \terminal{\# error } \opt{pp-tokens} new-line\br + \terminal{\# undef \ } identifier new-line\br + \terminal{\# line \ \ } pp-tokens new-line\br + \terminal{\# error \ } \opt{pp-tokens} new-line\br \terminal{\# warning} \opt{pp-tokens} new-line\br \terminal{\# pragma } \opt{pp-tokens} new-line\br \terminal{\# }new-line @@ -66,34 +67,33 @@ if-group \opt{elif-groups} \opt{else-group} endif-line \end{bnf} -\begin{bnf}\obeyspaces +\begin{bnf} \nontermdef{if-group}\br - \terminal{\# if } constant-expression new-line \opt{group}\br - \terminal{\# ifdef } identifier new-line \opt{group}\br + \terminal{\# if \ \ \ \ } constant-expression new-line \opt{group}\br + \terminal{\# ifdef \ } identifier new-line \opt{group}\br \terminal{\# ifndef } identifier new-line \opt{group} \end{bnf} \begin{bnf} \nontermdef{elif-groups}\br - elif-group\br - elif-groups elif-group + elif-group \opt{elif-groups} \end{bnf} -\begin{bnf}\obeyspaces +\begin{bnf} \nontermdef{elif-group}\br - \terminal{\# elif } constant-expression new-line \opt{group}\br + \terminal{\# elif \ \ \ } constant-expression new-line \opt{group}\br \terminal{\# elifdef } identifier new-line \opt{group}\br \terminal{\# elifndef} identifier new-line \opt{group} \end{bnf} -\begin{bnf}\obeyspaces +\begin{bnf} \nontermdef{else-group}\br - \terminal{\# else } new-line \opt{group} + \terminal{\# else \ \ } new-line \opt{group} \end{bnf} -\begin{bnf}\obeyspaces +\begin{bnf} \nontermdef{endif-line}\br - \terminal{\# endif } new-line + \terminal{\# endif \ } new-line \end{bnf} \begin{bnf} @@ -124,8 +124,48 @@ \begin{bnf} \nontermdef{pp-tokens}\br - preprocessing-token\br - pp-tokens preprocessing-token + preprocessing-token \opt{pp-tokens} +\end{bnf} + +\begin{bnf} +\nontermdef{embed-parameter-seq}\br + embed-parameter \opt{embed-parameter-seq} +\end{bnf} + +\begin{bnf} +\nontermdef{embed-parameter}\br + embed-standard-parameter\br + embed-prefixed-parameter +\end{bnf} + +\begin{bnf} +\nontermdef{embed-standard-parameter}\br + \terminal{limit} \terminal{(} pp-balanced-token-seq \terminal{)}\br + \terminal{prefix} \terminal{(} \opt{pp-balanced-token-seq} \terminal{)}\br + \terminal{suffix} \terminal{(} \opt{pp-balanced-token-seq} \terminal{)}\br + \terminal{if_empty} \terminal{(} \opt{pp-balanced-token-seq} \terminal{)} +\end{bnf} + +\begin{bnf} +\nontermdef{embed-prefixed-parameter}\br + identifier :: identifier\br + identifier :: identifier \terminal{(} \opt{pp-balanced-token-seq} \terminal{)} +\end{bnf} + +\begin{bnf} +\nontermdef{pp-balanced-token-seq}\br + pp-balanced-token \opt{pp-balanced-token-seq} +\end{bnf} + +\begin{bnf} +\nontermdef{pp-balanced-token}\br + \terminal{(} \opt{pp-balanced-token-seq} \terminal{)}\br + \terminal{[} \opt{pp-balanced-token-seq} \terminal{]}\br + \terminal{\{} \opt{pp-balanced-token-seq} \terminal{\}}\br + \textnormal{any} pp-token \textnormal{except:}\br + \bnfindent\textnormal{parenthesis (\unicode{0028}{left parenthesis} and \unicode{0029}{right parenthesis}),}\br + \bnfindent\textnormal{bracket (\unicode{005b}{left square bracket} and \unicode{005d}{right square bracket}), or}\br + \bnfindent\textnormal{brace (\unicode{007b}{left curly bracket} and \unicode{007d}{right curly bracket}).} \end{bnf} \begin{bnf} @@ -137,7 +177,7 @@ A \defn{preprocessing directive} consists of a sequence of preprocessing tokens that satisfies the following constraints: At the start of translation phase 4, -the first token in the sequence, +the first preprocessing token in the sequence, referred to as a \defnadj{directive-introducing}{token}, begins with the first character in the source file (optionally after whitespace containing no new-line characters) or @@ -150,7 +190,7 @@ \item an \keyword{import} preprocessing token -immediately followed on the same logical line by a +immediately followed on the same logical source line by a \grammarterm{header-name}, \tcode{<}, \grammarterm{identifier}, @@ -160,7 +200,7 @@ \item a \keyword{module} preprocessing token -immediately followed on the same logical line by an +immediately followed on the same logical source line by an \grammarterm{identifier}, \tcode{:}, or \tcode{;} @@ -168,11 +208,11 @@ \item an \keyword{export} preprocessing token -immediately followed on the same logical line by +immediately followed on the same logical source line by one of the two preceding forms. \end{itemize} -The last token in the sequence is the first token within the sequence that +The last preprocessing token in the sequence is the first preprocessing token within the sequence that is immediately followed by whitespace containing a new-line character. \begin{footnote} Thus, @@ -216,6 +256,16 @@ \pnum A sequence of preprocessing tokens is only a \grammarterm{text-line} if it does not begin with a directive-introducing token. +\begin{example} +\begin{codeblock} +using module = int; +module i; // not a \grammarterm{text-line} and not a \grammarterm{control-line} +int foo() { + return i; +} +\end{codeblock} +The example is not a valid \grammarterm{preprocessing-file}. +\end{example} A sequence of preprocessing tokens is only a \grammarterm{conditionally-supported-directive} if it does not begin with any of the directive names appearing after a \tcode{\#} in the syntax. @@ -224,6 +274,10 @@ \impldef{additional supported forms of preprocessing directive} semantics. +\pnum +Any \grammarterm{embed-prefixed-parameter} is conditionally-supported, +with \impldef{supported forms of \#embed prefix parameters} semantics. + \pnum At the start of phase 4 of translation, the \grammarterm{group} of a \grammarterm{pp-global-module-fragment} shall @@ -290,8 +344,7 @@ \begin{bnf} \nontermdef{h-pp-tokens}\br - h-preprocessing-token\br - h-pp-tokens h-preprocessing-token + h-preprocessing-token \opt{h-pp-tokens} \end{bnf} \begin{bnf} @@ -307,6 +360,12 @@ \terminal{\xname{has_include}} \terminal{(} header-name-tokens \terminal{)} \end{bnf} +\indextext{\idxxname{has_embed}}% +\begin{bnf} +\nontermdef{has-embed-expression}\br + \terminal{\xname{has_embed}} \terminal{(} pp-balanced-token-seq \terminal{)} +\end{bnf} + \indextext{\idxxname{has_cpp_attribute}}% \begin{bnf} \nontermdef{has-attribute-expression}\br @@ -325,9 +384,12 @@ all identifiers either are or are not macro names --- there simply are no keywords, enumeration constants, etc. \end{footnote} -and it may contain zero or more \grammarterm{defined-macro-expression}{s} and/or -\grammarterm{has-include-expression}{s} and/or -\grammarterm{has-attribute-expression}{s} as unary operator expressions. +and it may contain zero or more +\grammarterm{defined-macro-expression}{s}, +\grammarterm{has-include-expression}{s}, +\grammarterm{has-attribute-expression}{s}, +and/or \grammarterm{has-embed-expression}{s} +as unary operator expressions. \pnum A \grammarterm{defined-macro-expression} evaluates to \tcode{1} @@ -361,6 +423,31 @@ to \tcode{1} if the search for the source file succeeds, and to \tcode{0} if the search fails. +\pnum +The parenthesized \grammarterm{pp-balanced-token-seq} in each contained +\grammarterm{has-embed-expression} is processed as if that +\grammarterm{pp-balanced-token-seq} were the \grammarterm{pp-tokens} in the +third form of a \tcode{\#embed} directive\iref{cpp.embed}. +If such a directive would not satisfy the syntactic requirements of a +\tcode{\#embed} directive, the program is ill-formed. +The \grammarterm{has-embed-expression} evaluates to: +\begin{itemize} +\item +\mname{STDC_EMBED_FOUND} if the search for the resource succeeds, +all the given \grammarterm{embed-parameter}s in the \grammarterm{embed-parameter-seq} +are supported, and the resource is not empty. +\item +Otherwise, \mname{STDC_EMBED_EMPTY} if the search for the resource succeeds, +all the given \grammarterm{embed-parameter}s in the \grammarterm{embed-parameter-seq} +are supported, and the resource is empty. +\item +Otherwise, \mname{STDC_EMBED_NOT_FOUND}. +\end{itemize} +\begin{note} +An unrecognized \grammarterm{embed-parameter} in an \grammarterm{has-embed-expression} +is not ill-formed and is instead treated as not supported. +\end{note} + \pnum Each \grammarterm{has-attribute-expression} is replaced by a non-zero \grammarterm{pp-number} @@ -393,7 +480,6 @@ \topline \lhdr{Attribute} & \rhdr{Value} \\ \rowsep \tcode{assume} & \tcode{202207L} \\ -\tcode{carries_dependency} & \tcode{200809L} \\ \tcode{deprecated} & \tcode{201309L} \\ \tcode{fallthrough} & \tcode{201603L} \\ \tcode{likely} & \tcode{201803L} \\ @@ -409,9 +495,9 @@ \tcode{\#ifdef}, \tcode{\#ifndef}, \tcode{\#elifdef}, and \tcode{\#elifndef} directives, and the \tcode{defined} conditional inclusion operator, -shall treat \xname{has_include} and \xname{has_cpp_attribute} +shall treat \xname{has_include}, \xname{has_embed}, and \xname{has_cpp_attribute} as if they were the names of defined macros. -The identifiers \xname{has_include} and \xname{has_cpp_attribute} +The identifiers \xname{has_include}, \xname{has_embed}, and \xname{has_cpp_attribute} shall not appear in any context not mentioned in this subclause. \pnum @@ -422,11 +508,11 @@ \pnum Preprocessing directives of the forms -\begin{ncsimplebnf}\obeyspaces +\begin{ncsimplebnf} \indextext{\idxcode{\#if}}% -\terminal{\# if } constant-expression new-line \opt{group}\br +\terminal{\# if \ \ \ \ } constant-expression new-line \opt{group}\br \indextext{\idxcode{\#elif}}% -\terminal{\# elif } constant-expression new-line \opt{group} +\terminal{\# elif \ \ } constant-expression new-line \opt{group} \end{ncsimplebnf} check whether the controlling constant expression evaluates to nonzero. @@ -439,7 +525,7 @@ \tcode{defined} unary operator), just as in normal text. -If the token +If the preprocessing token \tcode{defined} is generated as a result of this replacement process or use of the @@ -452,7 +538,8 @@ After all replacements due to macro expansion and evaluations of \grammarterm{defined-macro-expression}s, -\grammarterm{has-include-expression}s, and +\grammarterm{has-include-expression}s, +\grammarterm{has-embed-expression}s, and \grammarterm{has-attribute-expression}s have been performed, all remaining identifiers and keywords, @@ -498,10 +585,10 @@ \pnum Preprocessing directives of the forms -\begin{ncsimplebnf}\obeyspaces -\terminal{\# ifdef } identifier new-line \opt{group}\br +\begin{ncsimplebnf} +\terminal{\# ifdef \ \ } identifier new-line \opt{group}\br \indextext{\idxcode{\#ifdef}}% -\terminal{\# ifndef } identifier new-line \opt{group}\br +\terminal{\# ifndef \ } identifier new-line \opt{group}\br \indextext{\idxcode{\#ifndef}}% \terminal{\# elifdef } identifier new-line \opt{group}\br \indextext{\idxcode{\#elifdef}}% @@ -661,13 +748,13 @@ If the directive resulting after all replacements does not match one of the two previous forms, the behavior is undefined. -\begin{footnote} -Note that adjacent \grammarterm{string-literal}s are not concatenated into +\begin{note} +Adjacent \grammarterm{string-literal}s are not concatenated into a single \grammarterm{string-literal} (see the translation phases in~\ref{lex.phases}); thus, an expansion that results in two \grammarterm{string-literal}s is an invalid directive. -\end{footnote} +\end{note} The method by which a sequence of preprocessing tokens between a \tcode{<} and a @@ -745,6 +832,356 @@ \end{codeblock} \end{example} +\rSec1[cpp.embed]{Resource inclusion} +\indextext{preprocessing directive!embed a resource} +\indextext{\idxcode{\#embed}}% + +\rSec2[cpp.embed.gen]{General} + +\pnum +A preprocessing directive of the form +\begin{ncsimplebnf} +\terminal{\# embed <} h-char-sequence \terminal{>} \opt{pp-tokens} new-line +\end{ncsimplebnf} +searches a sequence of +\impldef{sequence of places searched for an embedded resource} +places for a resource identified uniquely by the specified sequence between +the \tcode{<} and \tcode{>} delimiters. +How the places are specified or the resource identified is +\impldef{search locations for embedded resources specified with \tcode{<>}}. + +\pnum +A preprocessing directive of the form +\begin{ncsimplebnf} +\terminal{\# embed "} q-char-sequence \terminal{"} \opt{pp-tokens} new-line +\end{ncsimplebnf} +searches for a resource identified by the specified sequence between the +\tcode{"} delimiters. +The named resource is searched for in an +\impldef{manner of search for named resource} +manner. +If this search is not supported, or if the search fails, the directive is +reprocessed as if it read +\begin{ncsimplebnf} +\terminal{\# embed <} h-char-sequence \terminal{>} \opt{pp-tokens} new-line +\end{ncsimplebnf} +with the identical contained sequence (including \tcode{>} characters, if any) +from the original directive. + +\pnum +\recommended A mechanism similar to, but distinct from, the +\impldef{sequence of places searched for a header} +search paths used for \tcode{\#include} \iref{cpp.include} +is encouraged. + +\pnum +Either form of the \tcode{\#embed} directive processes the +\grammarterm{pp-tokens}, if present, just as in normal text. +The \grammarterm{pp-tokens} shall then have the form +\grammarterm{embed-parameter-seq}. + +\pnum +A resource is a source of data accessible from the translation environment. +A resource has an \defn{implementation-resource-width}, which is the +\impldef{size in bits of a resource} +size in bits of the resource. +If the implementation-resource-width is not an integral multiple of +\libmacro{CHAR_BIT}, the program is ill-formed. +Let \defn{implementation-resource-count} be +implementation-resource-width divided by \libmacro{CHAR_BIT}. +Every resource also has a \defn{resource-count}, which is + +\begin{itemize} +\item + the value as computed from the optionally-provided \tcode{limit} + \grammarterm{embed-parameter}\iref{cpp.embed.param.limit}, if present; +\item + otherwise, the implementation-resource-count. +\end{itemize} + +A resource is empty if the resource-count is zero. + +\pnum +\begin{example} +\begin{codeblock} +// ill-formed if the implementation-resource-width is 6 bits +#embed "6_bits.bin" +\end{codeblock} +\end{example} + +\pnum +The \tcode{\#embed} directive is replaced by a comma-delimited list of integer +literals of type \tcode{int}, unless otherwise modified by embed +parameters\iref{cpp.embed.param}. + +\pnum +The integer literals in the comma-delimited list correspond to +resource-count consecutive calls to \tcode{std::fgetc} \iref{cstdio.syn} +from the resource, as a binary file. +If any call to \tcode{std::fgetc} returns \tcode{EOF}, the program is +ill-formed. + +\pnum +\recommended The value of each integer literal should closely represent +the bit stream of the resource unmodified. +This can require an implementation to consider potential differences between +translation and execution environments, as well as any other applicable +sources of mismatch. + +\begin{example} +\begin{codeblock} +#include +#include +#include +#include +#include + +int main() { + // If the file is the same as the resource in the translation environment, no assert in this program should fail. + constexpr unsigned char d[] = { +#embed + }; + const std::vector vec_d = { +#embed + }; + + constexpr std::size_t expected_size = sizeof(d); + + // same file in execution environment as was embedded + std::ifstream f_source("data.dat", std::ios::binary | std::ios::in); + unsigned char runtime_d[expected_size]; + char* ifstream_ptr = reinterpret_cast(runtime_d); + assert(!f_source.read(ifstream_ptr, expected_size)); + std::size_t ifstream_size = f_source.gcount(); + assert (ifstream_size == expected_size); + int is_same = std::memcmp(&d[0], ifstream_ptr, ifstream_size); + assert(is_same == 0); + int is_same_vec = std::memcmp(vec_d.data(), ifstream_ptr, ifstream_size); + assert(is_same_vec == 0); +} +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +int i = { +#embed "i.dat" +}; // well-formed if \tcode{i.dat} produces a single value +int i2 = +#embed "i.dat" +; // also well-formed if \tcode{i.dat} produces a single value +struct s { + double a, b, c; + struct { double e, f, g; } x; + double h, i, j; +}; +s x = { +// well-formed if the directive produces nine or fewer values +#embed "s.dat" +}; +\end{codeblock} +\end{example} + +\pnum +A preprocessing directive of the form +\begin{ncsimplebnf} +\terminal{\# embed} pp-tokens new-line +\end{ncsimplebnf} +(that does not match one of the two previous forms) is permitted. +The preprocessing tokens after \tcode{embed} in the directive 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). +The directive resulting after all replacements of the third form shall match +one of the two previous forms. +\begin{note} +Adjacent \grammarterm{string-literal}{s} are not concatenated into a single +\grammarterm{string-literal} (see the translation phases in \iref{lex.phases}); +thus, an expansion that results in two \grammarterm{string-literal}{s} is an +invalid directive. +\end{note} + +Any further processing as in normal text described for the two previous +forms is not performed. +\begin{note} +That is, processing as in normal text happens once and only once for the entire +directive. +\end{note} + +\begin{example} +If the directive matches the third form, the whole directive is replaced. +If the directive matches the first two forms, everything after the name is +replaced. + +\begin{codeblock} +#define prefix(ARG) suffix(ARG) +#define THE_ADDITION "teehee" +#define THE_RESOURCE ":3c" +#embed ":3c" prefix(THE_ADDITION) +#embed THE_RESOURCE prefix(THE_ADDITION) +\end{codeblock} + +is equivalent to: + +\begin{codeblock} +#embed ":3c" suffix("teehee") +#embed ":3c" suffix("teehee") +\end{codeblock} +\end{example} + +\pnum +The method by which a sequence of preprocessing tokens between a \tcode{<} and +a \tcode{>} preprocessing token pair or a pair of \tcode{"} characters is +combined into a single resource name preprocessing token is +\impldef{search locations for \tcode{""""} resource}. + +\rSec2[cpp.embed.param]{Embed parameters} +\rSec3[cpp.embed.param.limit]{limit parameter} +\pnum +An \grammarterm{embed-parameter} of the form +\tcode{limit (} \grammarterm{pp-balanced-token-seq} \tcode{)} +specifies the +maximum possible number of elements in the comma-delimited list. +It shall appear at most once in the \grammarterm{embed-parameter-seq}. +The token \tcode{defined} shall not appear in the +\grammarterm{constant-expression}. + +\pnum +The \grammarterm{pp-balanced-token-seq} is evaluated as a +\grammarterm{constant-expression} using the rules as described in conditional +inclusion\iref{cpp.cond}, but without being processed as in normal text an +additional time. + +\begin{example} +\begin{codeblock} +#undef DATA_LIMIT +#if __has_embed( limit(DATA_LIMIT)) +#endif +\end{codeblock} + +is equivalent to: + +\begin{codeblock} +#if __has_embed( limit(0)) +#endif +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +#embed limit(__has_include("a.h")) + +#if __has_embed( limit(__has_include("a.h"))) +// ill-formed: \tcode{__has_include}\iref{cpp.cond} cannot appear here +#endif +\end{codeblock} +\end{example} + +\pnum +The \grammarterm{constant-expression} shall be an integral constant expression +whose value is greater than or equal to zero. +The resource-count\iref{cpp.embed.gen} becomes +implementation-resource-count, if the value of the +\grammarterm{constant-expression} is greater than +implementation-resource-count; otherwise, the value of the +\grammarterm{constant-expression}. +\begin{example} +\begin{codeblock} +constexpr unsigned char sound_signature[] = { + // a hypothetical resource capable of expanding to four or more elements +#embed limit(2+2) +}; + +static_assert(sizeof(sound_signature) == 4); // OK +\end{codeblock} +\end{example} + +\rSec3[cpp.embed.param.prefix]{prefix parameter} +\pnum +An \grammarterm{embed-parameter} of the form +\begin{ncsimplebnf} +\terminal{prefix (} \opt{pp-balanced-token-seq} \terminal{)} +\end{ncsimplebnf} +shall appear at most once in the \grammarterm{embed-parameter-seq}. + +\pnum +If the resource is empty, this \grammarterm{embed-parameter} is ignored. +Otherwise, the \grammarterm{pp-balanced-token-seq} is placed immediately +before the comma-delimited list of integral literals. + +\rSec3[cpp.embed.param.suffix]{suffix parameter} +\pnum +An \grammarterm{embed-parameter} of the form +\begin{ncsimplebnf} +\terminal{suffix (} \opt{pp-balanced-token-seq} \terminal{)} +\end{ncsimplebnf} +shall appear at most once in the \grammarterm{embed-parameter-seq}. + +\pnum +If the resource is empty, this \grammarterm{embed-parameter} is ignored. +Otherwise, the \grammarterm{pp-balanced-token-seq} is placed immediately after +the comma-delimited list of the integral constant expressions. + +\begin{example} +\begin{codeblock} +constexpr unsigned char whl[] = { +#embed "ches.glsl" \ + prefix(0xEF, 0xBB, 0xBF, ) /* a sequence of bytes */ \ + suffix(,) + 0 +}; +// always null-terminated, contains the sequence if not empty +constexpr bool is_empty = sizeof(whl) == 1 && whl[0] == '\0'; +constexpr bool is_not_empty = sizeof(whl) >= 4 + && whl[sizeof(whl) - 1] == '\0' + && whl[0] == '\xEF' && whl[1] == '\xBB' && whl[2] == '\xBF'; +static_assert(is_empty || is_not_empty); +\end{codeblock} +\end{example} + +\rSec3[cpp.embed.param.if.empty]{\tcode{if_empty} parameter} +\pnum +An embed-parameter of the form +\begin{ncsimplebnf} +\terminal{if_empty (} \opt{pp-balanced-token-seq} \terminal{)} +\end{ncsimplebnf} +shall appear at most once in the \grammarterm{embed-parameter-seq}. + +\pnum +If the resource is not empty, this \grammarterm{embed-parameter} is ignored. +Otherwise, the \tcode{\#embed} directive is replaced by the +\grammarterm{pp-balanced-token-seq}. + +\begin{example} +\tcode{limit(0)} affects when a resource is considered empty. +Therefore, the following program: + +\begin{codeblock} +#embed \ + if_empty(42203) limit(0) +\end{codeblock} +expands to +\begin{codeblock} +42203 +\end{codeblock} +\end{example} + +\begin{example} +This resource is considered empty due to the \tcode{limit(0)} \grammarterm{embed-parameter}, +always, including in \tcode{__has_embed} clauses. + +\begin{codeblock} +int infinity_zero () { +#if __has_embed( limit(0) prefix(some tokens)) == __STDC_EMBED_EMPTY__ + // if \tcode{} exists, this conditional inclusion branch is taken and the function returns \tcode{0}. + return 0; +#else + // otherwise, the resource does not exist +#error "The resource does not exist" +#endif +} +\end{codeblock} +\end{example} + \rSec1[cpp.module]{Module directive} \indextext{preprocessing directive!module}% @@ -756,9 +1193,35 @@ \pnum A \grammarterm{pp-module} shall not appear in a context where \tcode{module} -or (if it is the first token of the \grammarterm{pp-module}) \tcode{export} +or (if it is the first preprocessing token of the \grammarterm{pp-module}) \tcode{export} is an identifier defined as an object-like macro. +\pnum +The \grammarterm{pp-tokens}, if any, of a \grammarterm{pp-module} +shall be of the form: +\begin{ncsimplebnf} +pp-module-name \opt{pp-module-partition} \opt{pp-tokens} +\end{ncsimplebnf} +where the \grammarterm{pp-tokens} (if any) shall not begin with +a \tcode{(} preprocessing token and +the grammar non-terminals are defined as: +\begin{ncbnf} +\nontermdef{pp-module-name}\br + \opt{pp-module-name-qualifier} identifier +\end{ncbnf} +\begin{ncbnf} +\nontermdef{pp-module-partition}\br + \terminal{:} \opt{pp-module-name-qualifier} identifier +\end{ncbnf} +\begin{ncbnf} +\nontermdef{pp-module-name-qualifier}\br + identifier \terminal{.}\br + pp-module-name-qualifier identifier \terminal{.} +\end{ncbnf} +No \grammarterm{identifier} in +the \grammarterm{pp-module-name} or \grammarterm{pp-module-partition} +shall currently be defined as an object-like macro. + \pnum Any preprocessing tokens after the \tcode{module} preprocessing token in the \tcode{module} directive are processed just as in normal text. @@ -791,7 +1254,7 @@ \pnum A \grammarterm{pp-import} shall not appear in a context where \tcode{import} -or (if it is the first token of the \grammarterm{pp-import}) \tcode{export} +or (if it is the first preprocessing token of the \grammarterm{pp-import}) \tcode{export} is an identifier defined as an object-like macro. \pnum @@ -886,8 +1349,8 @@ \end{itemize} \pnum -\indextext{active macro directive|see{macro, active}}% -A macro directive is \defnx{active}{macro!active} at a source location +\indextext{active macro definition|see{macro, active}}% +A macro definition 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. @@ -1176,7 +1639,7 @@ For each parameter in the replacement list that is neither preceded by a \tcode{\#} or \tcode{\#\#} preprocessing token nor followed by a \tcode{\#\#} preprocessing token, the preprocessing tokens -naming the parameter are replaced by a token sequence determined as follows: +naming the parameter are replaced by a preprocessing token sequence determined as follows: \begin{itemize} \item If the parameter is of the form \grammarterm{va-opt-replacement}, @@ -1189,7 +1652,7 @@ macros contained therein have been expanded. The argument's preprocessing tokens are completely macro replaced before being substituted as if they formed the rest of the preprocessing - file with no other preprocessing tokens being available. + translation unit with no other preprocessing tokens being available. \end{itemize} \begin{example} \begin{codeblock} @@ -1382,7 +1845,7 @@ \end{note} If the result is not a valid preprocessing token, the behavior is undefined. -The resulting token is available for further macro replacement. +The resulting preprocessing token is available for further macro replacement. The order of evaluation of \tcode{\#\#} operators is unspecified. @@ -1425,7 +1888,7 @@ "hello, world" \end{codeblock} -Space around the \tcode{\#} and \tcode{\#\#} tokens in the macro definition +Space around the \tcode{\#} and \tcode{\#\#} preprocessing tokens in the macro definition is optional. \end{example} @@ -1451,8 +1914,8 @@ "x ## y" \end{codeblock} -In other words, expanding \tcode{hash_hash} produces a new token, -consisting of two adjacent sharp signs, but this new token is not the +In other words, expanding \tcode{hash_hash} produces a new preprocessing token, +consisting of two adjacent sharp signs, but this new preprocessing token is not the \tcode{\#\#} operator. \end{example} @@ -1574,10 +2037,12 @@ \pnum The \defn{line number} -of the current source line is one greater than +of the current source line is +the line number of the current physical source line, +i.e., it is one greater than the number of new-line characters read or introduced in translation phase 1\iref{lex.phases} -while processing the source file to the current token. +while processing the source file to the current preprocessing token. \pnum A preprocessing directive of the form @@ -1624,14 +2089,20 @@ \indextext{\idxcode{\#error}|see{preprocessing directive, error}} \pnum -A preprocessing directive of either of the following forms +A preprocessing directive of the form +\begin{ncsimplebnf} +\terminal{\# error} \opt{pp-tokens} new-line +\end{ncsimplebnf} +renders the program ill-formed. +A preprocessing directive of the form \begin{ncsimplebnf} -\terminal{\# error} \opt{pp-tokens} new-line\br \terminal{\# warning} \opt{pp-tokens} new-line \end{ncsimplebnf} -causes the implementation to produce -a diagnostic message that should include the specified sequence of preprocessing tokens; -the \tcode{\# error} directive renders the program ill-formed. +requires the implementation to produce at least one diagnostic message +for the preprocessing translation unit\iref{intro.compliance.general}. +\recommended +Any diagnostic message caused by either of these directives +should include the specified sequence of preprocessing tokens. \rSec1[cpp.pragma]{Pragma directive}% \indextext{preprocessing directive!pragma}% @@ -1672,7 +2143,7 @@ \xname{cplusplus}\\ The integer literal \tcode{\cppver}. \begin{note} -Future revisions of \Cpp{} will +Future revisions of this document will replace the value of this macro with a greater value. \end{note} @@ -1680,7 +2151,7 @@ The macros defined in \tref{cpp.predefined.ft} shall be defined to the corresponding integer literal. \begin{note} -Future revisions of \Cpp{} might replace +Future revisions of this document might replace the values of these macros with greater values. \end{note} @@ -1719,6 +2190,16 @@ The presumed line number can be changed by the \tcode{\#line} directive. \end{footnote} +\item +\indextext{stdc__embed_not_found__@\mname{STDC_EMBED_NOT_FOUND}}% +\indextext{stdc__embed_found__@\mname{STDC_EMBED_FOUND}}% +\indextext{stdc__embed_empty__@\mname{STDC_EMBED_EMPTY}}% +\mname{STDC_EMBED_NOT_FOUND}, \mname{STDC_EMBED_FOUND}, and \mname{STDC_EMBED_EMPTY}\\ +The integer literals \tcode{0}, \tcode{1}, and \tcode{2}, respectively. +\begin{note} +These represent values replaced from \grammarterm{has-embed-expression}{s}\iref{cpp.cond}. +\end{note} + \item \indextext{__stdc_hosted__@\mname{STDC_HOSTED}}% \indextext{implementation!hosted}% @@ -1746,7 +2227,7 @@ \mname{STDCPP_FLOAT16_T}\\ Defined as the integer literal \tcode{1} if and only if the implementation supports -the ISO/IEC/IEEE 60559 floating-point interchange format binary16 +the \IsoFloatUndated{} floating-point interchange format binary16 as an extended floating-point type\iref{basic.extended.fp}. \item @@ -1754,7 +2235,7 @@ \mname{STDCPP_FLOAT32_T}\\ Defined as the integer literal \tcode{1} if and only if the implementation supports -the ISO/IEC/IEEE 60559 floating-point interchange format binary32 +the \IsoFloatUndated{} floating-point interchange format binary32 as an extended floating-point type. \item @@ -1762,7 +2243,7 @@ \mname{STDCPP_FLOAT64_T}\\ Defined as the integer literal \tcode{1} if and only if the implementation supports -the ISO/IEC/IEEE 60559 floating-point interchange format binary64 +the \IsoFloatUndated{} floating-point interchange format binary64 as an extended floating-point type. \item @@ -1770,7 +2251,7 @@ \mname{STDCPP_FLOAT128_T}\\ Defined as the integer literal \tcode{1} if and only if the implementation supports -the ISO/IEC/IEEE 60559 floating-point interchange format binary128 +the \IsoFloatUndated{} floating-point interchange format binary128 as an extended floating-point type. \item @@ -1816,15 +2297,18 @@ \defnxname{cpp_char8_t} & \tcode{202207L} \\ \rowsep \defnxname{cpp_concepts} & \tcode{202002L} \\ \rowsep \defnxname{cpp_conditional_explicit} & \tcode{201806L} \\ \rowsep -\defnxname{cpp_constexpr} & \tcode{202306L} \\ \rowsep +\defnxname{cpp_constexpr} & \tcode{202406L} \\ \rowsep \defnxname{cpp_constexpr_dynamic_alloc} & \tcode{201907L} \\ \rowsep +\defnxname{cpp_constexpr_exceptions} & \tcode{202411L} \\ \rowsep \defnxname{cpp_constexpr_in_decltype} & \tcode{201711L} \\ \rowsep \defnxname{cpp_consteval} & \tcode{202211L} \\ \rowsep \defnxname{cpp_constinit} & \tcode{201907L} \\ \rowsep +\defnxname{cpp_contracts} & \tcode{202502L} \\ \rowsep \defnxname{cpp_decltype} & \tcode{200707L} \\ \rowsep \defnxname{cpp_decltype_auto} & \tcode{201304L} \\ \rowsep \defnxname{cpp_deduction_guides} & \tcode{201907L} \\ \rowsep \defnxname{cpp_delegating_constructors} & \tcode{200604L} \\ \rowsep +\defnxname{cpp_deleted_function} & \tcode{202403L} \\ \rowsep \defnxname{cpp_designated_initializers} & \tcode{201707L} \\ \rowsep \defnxname{cpp_enumerator_attributes} & \tcode{201411L} \\ \rowsep \defnxname{cpp_explicit_this_parameter} & \tcode{202110L} \\ \rowsep @@ -1851,7 +2335,9 @@ \defnxname{cpp_nontype_template_args} & \tcode{201911L} \\ \rowsep \defnxname{cpp_nontype_template_parameter_auto} & \tcode{201606L} \\ \rowsep \defnxname{cpp_nsdmi} & \tcode{200809L} \\ \rowsep +\defnxname{cpp_pack_indexing} & \tcode{202311L} \\ \rowsep \defnxname{cpp_placeholder_variables} & \tcode{202306L} \\ \rowsep +\defnxname{cpp_pp_embed} & \tcode{202502L} \\ \rowsep \defnxname{cpp_range_based_for} & \tcode{202211L} \\ \rowsep \defnxname{cpp_raw_strings} & \tcode{200710L} \\ \rowsep \defnxname{cpp_ref_qualifiers} & \tcode{200710L} \\ \rowsep @@ -1861,14 +2347,18 @@ \defnxname{cpp_sized_deallocation} & \tcode{201309L} \\ \rowsep \defnxname{cpp_static_assert} & \tcode{202306L} \\ \rowsep \defnxname{cpp_static_call_operator} & \tcode{202207L} \\ \rowsep -\defnxname{cpp_structured_bindings} & \tcode{201606L} \\ \rowsep +\defnxname{cpp_structured_bindings} & \tcode{202411L} \\ \rowsep +\defnxname{cpp_template_parameters} & \tcode{202502L} \\ \rowsep \defnxname{cpp_template_template_args} & \tcode{201611L} \\ \rowsep \defnxname{cpp_threadsafe_static_init} & \tcode{200806L} \\ \rowsep +\defnxname{cpp_trivial_relocatability} & \tcode{202502L} \\ \rowsep +\defnxname{cpp_trivial_union} & \tcode{202502L} \\ \rowsep \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_friend} & \tcode{202403L} \\ \rowsep \defnxname{cpp_variadic_templates} & \tcode{200704L} \\ \rowsep \defnxname{cpp_variadic_using} & \tcode{201611L} \\ \end{LongTable} diff --git a/source/ranges.tex b/source/ranges.tex index 2a455af9e2..c16eba7f10 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -27,6 +27,7 @@ \indexheader{ranges}% \indexlibraryglobal{all_t}% \begin{codeblock} +// mostly freestanding #include // see \ref{compare.syn} #include // see \ref{initializer.list.syn} #include // see \ref{iterator.synopsis} @@ -34,170 +35,174 @@ namespace std::ranges { inline namespace @\unspec@ { // \ref{range.access}, range access - inline constexpr @\unspec@ begin = @\unspec@; // freestanding - inline constexpr @\unspec@ end = @\unspec@; // freestanding - inline constexpr @\unspec@ cbegin = @\unspec@; // freestanding - inline constexpr @\unspec@ cend = @\unspec@; // freestanding - inline constexpr @\unspec@ rbegin = @\unspec@; // freestanding - inline constexpr @\unspec@ rend = @\unspec@; // freestanding - inline constexpr @\unspec@ crbegin = @\unspec@; // freestanding - inline constexpr @\unspec@ crend = @\unspec@; // freestanding - - inline constexpr @\unspec@ size = @\unspec@; // freestanding - inline constexpr @\unspec@ ssize = @\unspec@; // freestanding - inline constexpr @\unspec@ empty = @\unspec@; // freestanding - inline constexpr @\unspec@ data = @\unspec@; // freestanding - inline constexpr @\unspec@ cdata = @\unspec@; // freestanding + inline constexpr @\unspec@ begin = @\unspec@; + inline constexpr @\unspec@ end = @\unspec@; + inline constexpr @\unspec@ cbegin = @\unspec@; + inline constexpr @\unspec@ cend = @\unspec@; + inline constexpr @\unspec@ rbegin = @\unspec@; + inline constexpr @\unspec@ rend = @\unspec@; + inline constexpr @\unspec@ crbegin = @\unspec@; + inline constexpr @\unspec@ crend = @\unspec@; + + inline constexpr @\unspec@ size = @\unspec@; + inline constexpr @\unspec@ reserve_hint = @\unspec@; + inline constexpr @\unspec@ ssize = @\unspec@; + inline constexpr @\unspec@ empty = @\unspec@; + inline constexpr @\unspec@ data = @\unspec@; + inline constexpr @\unspec@ cdata = @\unspec@; } // \ref{range.range}, ranges template - concept range = @\seebelow@; // freestanding + concept range = @\seebelow@; template - constexpr bool enable_borrowed_range = false; // freestanding + constexpr bool enable_borrowed_range = false; template - concept borrowed_range = @\seebelow@; // freestanding + concept borrowed_range = @\seebelow@; template - using iterator_t = decltype(ranges::begin(declval())); // freestanding + using iterator_t = decltype(ranges::begin(declval())); template<@\libconcept{range}@ R> - using sentinel_t = decltype(ranges::end(declval())); // freestanding + using sentinel_t = decltype(ranges::end(declval())); template<@\libconcept{range}@ R> - using const_iterator_t = const_iterator>; // freestanding + using const_iterator_t = decltype(ranges::cbegin(declval())); template<@\libconcept{range}@ R> - using const_sentinel_t = const_sentinel>; // freestanding + using const_sentinel_t = decltype(ranges::cend(declval())); template<@\libconcept{range}@ R> - using range_difference_t = iter_difference_t>; // freestanding + using range_difference_t = iter_difference_t>; template<@\libconcept{sized_range}@ R> - using range_size_t = decltype(ranges::size(declval())); // freestanding + using range_size_t = decltype(ranges::size(declval())); template<@\libconcept{range}@ R> - using range_value_t = iter_value_t>; // freestanding + using range_value_t = iter_value_t>; template<@\libconcept{range}@ R> - using range_reference_t = iter_reference_t>; // freestanding + using range_reference_t = iter_reference_t>; template<@\libconcept{range}@ R> - using range_const_reference_t = iter_const_reference_t>; // freestanding + using range_const_reference_t = iter_const_reference_t>; template<@\libconcept{range}@ R> - using range_rvalue_reference_t = iter_rvalue_reference_t>; // freestanding + using range_rvalue_reference_t = iter_rvalue_reference_t>; template<@\libconcept{range}@ R> - using range_common_reference_t = iter_common_reference_t>; // freestanding + using range_common_reference_t = iter_common_reference_t>; // \ref{range.sized}, sized ranges template - constexpr bool disable_sized_range = false; // freestanding + constexpr bool disable_sized_range = false; template - concept sized_range = @\seebelow@; // freestanding + concept approximately_sized_range = @\seebelow@; + + template + concept sized_range = @\seebelow@; // \ref{range.view}, views template - constexpr bool enable_view = @\seebelow@; // freestanding + constexpr bool enable_view = @\seebelow@; - struct view_base {}; // freestanding + struct view_base {}; template - concept view = @\seebelow@; // freestanding + concept view = @\seebelow@; // \ref{range.refinements}, other range refinements template - concept output_range = @\seebelow@; // freestanding + concept output_range = @\seebelow@; template - concept input_range = @\seebelow@; // freestanding + concept input_range = @\seebelow@; template - concept forward_range = @\seebelow@; // freestanding + concept forward_range = @\seebelow@; template - concept bidirectional_range = @\seebelow@; // freestanding + concept bidirectional_range = @\seebelow@; template - concept random_access_range = @\seebelow@; // freestanding + concept random_access_range = @\seebelow@; template - concept contiguous_range = @\seebelow@; // freestanding + concept contiguous_range = @\seebelow@; template - concept common_range = @\seebelow@; // freestanding + concept common_range = @\seebelow@; template - concept viewable_range = @\seebelow@; // freestanding + concept viewable_range = @\seebelow@; template - concept constant_range = @\seebelow@; // freestanding + concept constant_range = @\seebelow@; // \ref{view.interface}, class template \tcode{view_interface} template requires is_class_v && @\libconcept{same_as}@> - class view_interface; // freestanding + class view_interface; // \ref{range.subrange}, sub-ranges - enum class @\libglobal{subrange_kind}@ : bool { @\libmember{unsized}{subrange_kind}@, @\libmember{sized}{subrange_kind}@ }; // freestanding + enum class @\libglobal{subrange_kind}@ : bool { @\libmember{unsized}{subrange_kind}@, @\libmember{sized}{subrange_kind}@ }; template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sentinel_for}@ S = I, subrange_kind K = @\seebelow@> requires (K == subrange_kind::sized || !@\libconcept{sized_sentinel_for}@) - class subrange; // freestanding + class subrange; template - constexpr bool @\libspec{enable_borrowed_range}{subrange}@> = true; // freestanding + constexpr bool @\libspec{enable_borrowed_range}{subrange}@> = true; template requires ((N == 0 && @\libconcept{copyable}@) || N == 1) - constexpr auto get(const subrange& r); // freestanding + constexpr auto get(const subrange& r); template requires (N < 2) - constexpr auto get(subrange&& r); // freestanding + constexpr auto get(subrange&& r); } namespace std { - using ranges::get; // freestanding + using ranges::get; } namespace std::ranges { // \ref{range.dangling}, dangling iterator handling - struct dangling; // freestanding + struct dangling; // \ref{range.elementsof}, class template \tcode{elements_of} template<@\libconcept{range}@ R, class Allocator = allocator> - struct elements_of; + struct elements_of; // hosted template<@\libconcept{range}@ R> - using borrowed_iterator_t = @\seebelow@; // freestanding + using borrowed_iterator_t = @\seebelow@; template<@\libconcept{range}@ R> - using borrowed_subrange_t = @\seebelow@; // freestanding + using borrowed_subrange_t = @\seebelow@; // \ref{range.utility.conv}, range conversions template requires (!@\libconcept{view}@) - constexpr C to(R&& r, Args&&... args); // freestanding + constexpr C to(R&& r, Args&&... args); template class C, @\libconcept{input_range}@ R, class... Args> - constexpr auto to(R&& r, Args&&... args); // freestanding + constexpr auto to(R&& r, Args&&... args); template requires (!@\libconcept{view}@) - constexpr auto to(Args&&... args); // freestanding + constexpr auto to(Args&&... args); template class C, class... Args> - constexpr auto to(Args&&... args); // freestanding + constexpr auto to(Args&&... args); // \ref{range.empty}, empty view template requires is_object_v - class empty_view; // freestanding + class empty_view; template - constexpr bool @\libspec{enable_borrowed_range}{empty_view}@> = true; // freestanding + constexpr bool @\libspec{enable_borrowed_range}{empty_view}@> = true; namespace views { template - constexpr empty_view @\libmember{empty}{views}@{}; // freestanding + constexpr empty_view @\libmember{empty}{views}@{}; } // \ref{range.single}, single view template<@\libconcept{move_constructible}@ T> requires is_object_v - class single_view; // freestanding + class single_view; - namespace views { inline constexpr @\unspecnc@ single = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ single = @\unspecnc@; } template using @\exposidnc{maybe-const}@ = conditional_t; // \expos @@ -205,145 +210,142 @@ // \ref{range.iota}, iota view template<@\libconcept{weakly_incrementable}@ W, @\libconcept{semiregular}@ Bound = unreachable_sentinel_t> requires @\exposconcept{weakly-equality-comparable-with}@ && @\libconcept{copyable}@ - class iota_view; // freestanding + class iota_view; template - constexpr bool @\libspec{enable_borrowed_range}{iota_view}@> = true; // freestanding + constexpr bool @\libspec{enable_borrowed_range}{iota_view}@> = true; - namespace views { inline constexpr @\unspecnc@ iota = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ iota = @\unspecnc@; } // \ref{range.repeat}, repeat view template<@\libconcept{move_constructible}@ T, @\libconcept{semiregular}@ Bound = unreachable_sentinel_t> requires @\seebelow@ - class repeat_view; // freestanding + class repeat_view; - namespace views { inline constexpr @\unspecnc@ repeat = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ repeat = @\unspecnc@; } // \ref{range.istream}, istream view template<@\libconcept{movable}@ Val, class CharT, class Traits = char_traits> requires @\seebelow@ - class basic_istream_view; + class basic_istream_view; // hosted template - using istream_view = basic_istream_view; + using istream_view = basic_istream_view; // hosted template - using wistream_view = basic_istream_view; + using wistream_view = basic_istream_view; // hosted - namespace views { template constexpr @\unspecnc@ istream = @\unspecnc@; } + namespace views { + template constexpr @\unspecnc@ istream = @\unspecnc@; // hosted + } // \ref{range.adaptor.object}, range adaptor objects template requires is_class_v && @\libconcept{same_as}@> - class range_adaptor_closure { }; // freestanding + class range_adaptor_closure { }; // \ref{range.all}, all view namespace views { - inline constexpr @\unspecnc@ all = @\unspecnc@; // freestanding + inline constexpr @\unspecnc@ all = @\unspecnc@; template<@\libconcept{viewable_range}@ R> - using all_t = decltype(all(declval())); // freestanding + using all_t = decltype(all(declval())); } // \ref{range.ref.view}, ref view template<@\libconcept{range}@ R> requires is_object_v - class ref_view; // freestanding + class ref_view; template - constexpr bool @\libspec{enable_borrowed_range}{ref_view}@> = true; // freestanding + constexpr bool @\libspec{enable_borrowed_range}{ref_view}@> = true; // \ref{range.owning.view}, owning view template<@\libconcept{range}@ R> requires @\seebelow@ - class owning_view; // freestanding + class owning_view; template - constexpr bool @\libspec{enable_borrowed_range}{owning_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{owning_view}@> = enable_borrowed_range; // \ref{range.as.rvalue}, as rvalue view template<@\libconcept{view}@ V> requires @\libconcept{input_range}@ - class as_rvalue_view; // freestanding + class as_rvalue_view; template - constexpr bool @\libspec{enable_borrowed_range}{as_rvalue_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{as_rvalue_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ as_rvalue = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ as_rvalue = @\unspecnc@; } // \ref{range.filter}, filter view template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> requires @\libconcept{view}@ && is_object_v - class filter_view; // freestanding + class filter_view; - namespace views { inline constexpr @\unspecnc@ filter = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ filter = @\unspecnc@; } // \ref{range.transform}, transform view template<@\libconcept{input_range}@ V, @\libconcept{move_constructible}@ F> requires @\libconcept{view}@ && is_object_v && @\libconcept{regular_invocable}@> && @\exposconcept{can-reference}@>> - class transform_view; // freestanding + class transform_view; - namespace views { inline constexpr @\unspecnc@ transform = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ transform = @\unspecnc@; } // \ref{range.take}, take view - template<@\libconcept{view}@> class take_view; // freestanding + template<@\libconcept{view}@> class take_view; template - constexpr bool @\libspec{enable_borrowed_range}{take_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{take_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ take = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ take = @\unspecnc@; } // \ref{range.take.while}, take while view template<@\libconcept{view}@ V, class Pred> requires @\libconcept{input_range}@ && is_object_v && @\libconcept{indirect_unary_predicate}@> - class take_while_view; // freestanding + class take_while_view; - namespace views { inline constexpr @\unspecnc@ take_while = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ take_while = @\unspecnc@; } // \ref{range.drop}, drop view template<@\libconcept{view}@ V> - class drop_view; // freestanding + class drop_view; template - constexpr bool @\libspec{enable_borrowed_range}{drop_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{drop_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ drop = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ drop = @\unspecnc@; } // \ref{range.drop.while}, drop while view template<@\libconcept{view}@ V, class Pred> requires @\libconcept{input_range}@ && is_object_v && @\libconcept{indirect_unary_predicate}@> - class drop_while_view; // freestanding + class drop_while_view; template - constexpr bool @\libspec{enable_borrowed_range}{drop_while_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{drop_while_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ drop_while = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ drop_while = @\unspecnc@; } // \ref{range.join}, join view template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ && @\libconcept{input_range}@> - class join_view; // freestanding + class join_view; - namespace views { inline constexpr @\unspecnc@ join = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ join = @\unspecnc@; } // \ref{range.join.with}, join with view - template - concept @\exposconcept{compatible-joinable-ranges}@ = @\seebelow@; // \expos - template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> - requires @\libconcept{view}@ && @\libconcept{input_range}@> - && @\libconcept{view}@ - && @\exposconcept{compatible-joinable-ranges}@, Pattern> - class join_with_view; // freestanding + requires @\seebelow@ + class join_with_view; - namespace views { inline constexpr @\unspecnc@ join_with = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ join_with = @\unspecnc@; } // \ref{range.lazy.split}, lazy split view template @@ -353,48 +355,55 @@ requires @\libconcept{view}@ && @\libconcept{view}@ && @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) - class lazy_split_view; // freestanding + class lazy_split_view; // \ref{range.split}, split view - template<@\libconcept{forward_range}@ V, @\libconcept{forward_range}@ Pattern> - requires @\libconcept{view}@ && @\libconcept{view}@ && - @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> - class split_view; // freestanding + template<@\libconcept{forward_range}@ V, @\libconcept{forward_range}@ Pattern> + requires @\libconcept{view}@ && @\libconcept{view}@ && + @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> + class split_view; namespace views { - inline constexpr @\unspecnc@ lazy_split = @\unspecnc@; // freestanding - inline constexpr @\unspecnc@ split = @\unspecnc@; // freestanding + inline constexpr @\unspecnc@ lazy_split = @\unspecnc@; + inline constexpr @\unspecnc@ split = @\unspecnc@; } + // \ref{range.concat}, concat view + template<@\libconcept{input_range}@... Views> + requires @\seebelow@ + class concat_view; + + namespace views { inline constexpr @\unspecnc@ concat = @\unspecnc@; } + // \ref{range.counted}, counted view - namespace views { inline constexpr @\unspecnc@ counted = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ counted = @\unspecnc@; } // \ref{range.common}, common view template<@\libconcept{view}@ V> requires (!@\libconcept{common_range}@ && @\libconcept{copyable}@>) - class common_view; // freestanding + class common_view; template - constexpr bool @\libspec{enable_borrowed_range}{common_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{common_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ common = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ common = @\unspecnc@; } // \ref{range.reverse}, reverse view template<@\libconcept{view}@ V> requires @\libconcept{bidirectional_range}@ - class reverse_view; // freestanding + class reverse_view; template - constexpr bool @\libspec{enable_borrowed_range}{reverse_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{reverse_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ reverse = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ reverse = @\unspecnc@; } // \ref{range.as.const}, as const view template<@\libconcept{input_range}@ R> - constexpr auto& @\exposid{possibly-const-range}@(R& r) { // \expos - if constexpr (@\libconcept{constant_range}@ && !@\libconcept{constant_range}@) { + constexpr auto& @\exposid{possibly-const-range}@(R& r) noexcept { // \expos + if constexpr (@\libconcept{input_range}@) { return const_cast(r); } else { return r; @@ -403,172 +412,190 @@ template<@\libconcept{view}@ V> requires @\libconcept{input_range}@ - class as_const_view; // freestanding + class as_const_view; template - constexpr bool @\libspec{enable_borrowed_range}{as_const_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{as_const_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ as_const = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ as_const = @\unspecnc@; } // \ref{range.elements}, elements view template<@\libconcept{input_range}@ V, size_t N> requires @\seebelow@ - class elements_view; // freestanding + class elements_view; template - constexpr bool @\libspec{enable_borrowed_range}{elements_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{elements_view}@> = enable_borrowed_range; template - using @\libglobal{keys_view}@ = elements_view; // freestanding + using @\libglobal{keys_view}@ = elements_view; template - using @\libglobal{values_view}@ = elements_view; // freestanding + using @\libglobal{values_view}@ = elements_view; namespace views { template - constexpr @\unspecnc@ elements = @\unspecnc@; // freestanding - inline constexpr auto @\libmember{keys}{views}@ = elements<0>; // freestanding - inline constexpr auto @\libmember{values}{views}@ = elements<1>; // freestanding + constexpr @\unspecnc@ elements = @\unspecnc@; + inline constexpr auto @\libmember{keys}{views}@ = elements<0>; + inline constexpr auto @\libmember{values}{views}@ = elements<1>; } // \ref{range.enumerate}, enumerate view template<@\libconcept{view}@ V> requires @\seebelow@ - class enumerate_view; // freestanding + class enumerate_view; template - constexpr bool @\libspec{enable_borrowed_range}{enumerate_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{enumerate_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ enumerate = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ enumerate = @\unspecnc@; } // \ref{range.zip}, zip view template<@\libconcept{input_range}@... Views> requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) - class zip_view; // freestanding + class zip_view; template - constexpr bool @\libspec{enable_borrowed_range}{zip_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{zip_view}@> = (enable_borrowed_range && ...); - namespace views { inline constexpr @\unspecnc@ zip = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ zip = @\unspecnc@; } // \ref{range.zip.transform}, zip transform view template<@\libconcept{move_constructible}@ F, @\libconcept{input_range}@... Views> requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && is_object_v && @\libconcept{regular_invocable}@...> && @\exposconcept{can-reference}@...>> - class zip_transform_view; // freestanding + class zip_transform_view; - namespace views { inline constexpr @\unspecnc@ zip_transform = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ zip_transform = @\unspecnc@; } // \ref{range.adjacent}, adjacent view template<@\libconcept{forward_range}@ V, size_t N> requires @\libconcept{view}@ && (N > 0) - class adjacent_view; // freestanding + class adjacent_view; template - constexpr bool @\libspec{enable_borrowed_range}{adjacent_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{adjacent_view}@> = enable_borrowed_range; namespace views { template - constexpr @\unspecnc@ adjacent = @\unspecnc@; // freestanding - inline constexpr auto @\libmember{pairwise}{views}@ = adjacent<2>; // freestanding + constexpr @\unspecnc@ adjacent = @\unspecnc@; + inline constexpr auto @\libmember{pairwise}{views}@ = adjacent<2>; } // \ref{range.adjacent.transform}, adjacent transform view template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> requires @\seebelow@ - class adjacent_transform_view; // freestanding + class adjacent_transform_view; namespace views { template - constexpr @\unspecnc@ adjacent_transform = @\unspecnc@; // freestanding - inline constexpr auto @\libmember{pairwise_transform}{views}@ = adjacent_transform<2>; // freestanding + constexpr @\unspecnc@ adjacent_transform = @\unspecnc@; + inline constexpr auto @\libmember{pairwise_transform}{views}@ = adjacent_transform<2>; } // \ref{range.chunk}, chunk view template<@\libconcept{view}@ V> requires @\libconcept{input_range}@ - class chunk_view; // freestanding + class chunk_view; template<@\libconcept{view}@ V> requires @\libconcept{forward_range}@ - class chunk_view; // freestanding + class chunk_view; template - constexpr bool @\libspec{enable_borrowed_range}{chunk_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{chunk_view}@> = @\libconcept{forward_range}@ && enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ chunk = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ chunk = @\unspecnc@; } // \ref{range.slide}, slide view template<@\libconcept{forward_range}@ V> requires @\libconcept{view}@ - class slide_view; // freestanding + class slide_view; template - constexpr bool @\libspec{enable_borrowed_range}{slide_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{slide_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ slide = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ slide = @\unspecnc@; } // \ref{range.chunk.by}, chunk by view template<@\libconcept{forward_range}@ V, @\libconcept{indirect_binary_predicate}@, iterator_t> Pred> requires @\libconcept{view}@ && is_object_v - class chunk_by_view; // freestanding + class chunk_by_view; - namespace views { inline constexpr @\unspecnc@ chunk_by = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ chunk_by = @\unspecnc@; } // \ref{range.stride}, stride view template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ - class stride_view; // freestanding + class stride_view; template - constexpr bool @\libspec{enable_borrowed_range}{stride_view}@> = // freestanding + constexpr bool @\libspec{enable_borrowed_range}{stride_view}@> = enable_borrowed_range; - namespace views { inline constexpr @\unspecnc@ stride = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ stride = @\unspecnc@; } // \ref{range.cartesian}, cartesian product view template<@\libconcept{input_range}@ First, @\libconcept{forward_range}@... Vs> requires (@\libconcept{view}@ && ... && @\libconcept{view}@) - class cartesian_product_view; // freestanding + class cartesian_product_view; - namespace views { inline constexpr @\unspecnc@ cartesian_product = @\unspecnc@; } // freestanding + namespace views { inline constexpr @\unspecnc@ cartesian_product = @\unspecnc@; } + + // \ref{range.cache.latest}, cache latest view + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class cache_latest_view; + + namespace views { inline constexpr @\unspec@ cache_latest = @\unspec@; } + + // \ref{range.to.input}, to input view + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class to_input_view; + + template + constexpr bool enable_borrowed_range> = + enable_borrowed_range; + + namespace views { inline constexpr @\unspec@ to_input = @\unspec@; } } namespace std { - namespace views = ranges::views; // freestanding + namespace views = ranges::views; - template struct tuple_size; // freestanding - template struct tuple_element; // freestanding + template struct tuple_size; + template struct tuple_element; template - struct tuple_size> // freestanding + struct tuple_size> : integral_constant {}; template - struct tuple_element<0, ranges::subrange> { // freestanding + struct tuple_element<0, ranges::subrange> { using type = I; }; template - struct tuple_element<1, ranges::subrange> { // freestanding + struct tuple_element<1, ranges::subrange> { using type = S; }; template - struct tuple_element<0, const ranges::subrange> { // freestanding + struct tuple_element<0, const ranges::subrange> { using type = I; }; template - struct tuple_element<1, const ranges::subrange> { // freestanding + struct tuple_element<1, const ranges::subrange> { using type = S; }; - struct from_range_t { explicit from_range_t() = default; }; // freestanding - inline constexpr from_range_t from_range{}; // freestanding + struct from_range_t { explicit from_range_t() = default; }; + inline constexpr from_range_t from_range{}; } \end{codeblock} @@ -600,7 +627,7 @@ \pnum In addition to being available via inclusion of the \libheader{ranges} header, the customization point objects in \ref{range.access} are -available when \libheaderrefx{iterator}{iterator.synopsis} is included. +available when the header \libheaderrefx{iterator}{iterator.synopsis} is included. \pnum Within \ref{range.access}, @@ -1075,6 +1102,50 @@ \tcode{ranges::ssize(E)} is expression-equivalent to \tcode{static_cast(ranges::size(t))}. +\rSec2[range.prim.size.hint]{\tcode{ranges::reserve_hint}} +\indexlibraryglobal{reserve_hint}% + +\pnum +The name \tcode{ranges::reserve_hint} denotes +a customization point object\iref{customization.point.object}. + +\pnum +Given a subexpression \tcode{E} with type \tcode{T}, +let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}. +Then: +\begin{itemize} +\item +If \tcode{ranges::size(E)} is a valid expression, +\tcode{ranges::reserve_hint(E)} is expression-equivalent to +\tcode{ranges::size(E)}. +\item +Otherwise, +if \tcode{auto(t.reserve_hint())} is a valid expression of +integer-like type\iref{iterator.concept.winc}, +\tcode{ranges::re\-serve_hint(E)} is expression-equivalent to +\tcode{auto(t.reserve_hint())}. +\item +Otherwise, +if \tcode{T} is a class or enumeration type and +\tcode{auto(reserve_hint(t))} is a valid expression of +integer-like type where +the meaning of \tcode{reserve_hint} is established as-if by +performing argument-dependent lookup only\iref{basic.lookup.argdep}, then +\tcode{ranges::reserve_hint(E)} is expression-equivalent to that expression. +\item +Otherwise, +\tcode{ranges::reserve_hint(E)} is ill-formed. +\end{itemize} +\begin{note} +Diagnosable ill-formed cases above result in substitution failure when +\tcode{ranges::reserve_hint(E)} appears in the immediate context of +a template instantiation. +\end{note} +\begin{note} +Whenever \tcode{ranges::reserve_hint(E)} is a valid expression, +its type is integer-like. +\end{note} + \rSec2[range.prim.empty]{\tcode{ranges::empty}} \indexlibraryglobal{empty}% @@ -1184,7 +1255,7 @@ \begin{codeblock} template -constexpr auto @\exposid{as-const-pointer}@(const T* p) { return p; } // \expos +constexpr auto @\exposid{as-const-pointer}@(const T* p) noexcept { return p; } // \expos \end{codeblock} \pnum @@ -1352,17 +1423,58 @@ \end{example} \end{itemdescr} +\rSec2[range.approximately.sized]{Approximately sized ranges} + +\pnum +The \libconcept{approximately_sized_range} concept refines \libconcept{range} +with the requirement that +an approximation of the number of elements in the range +can be determined in amortized constant time using \tcode{ranges::reserve_hint}. + +\begin{itemdecl} +template + concept @\deflibconcept{approximately_sized_range}@ = + @\libconcept{range}@ && requires(T& t) { ranges::reserve_hint(t); }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Given an lvalue \tcode{t} of type \tcode{remove_reference_t}, +\tcode{T} models \libconcept{approximately_sized_range} only if +\begin{itemize} +\item +\tcode{ranges::reserve_hint(t)} is amortized \bigoh{1}, +does not modify \tcode{t}, and +has a value that +is not negative and is representable in \tcode{range_difference_t}, and +\item +if \tcode{iterator_t} models \libconcept{forward_iterator}, +\tcode{ranges::reserve_hint(t)} is well-defined +regardless of the evaluation of \tcode{ranges::begin(t)}. +\begin{note} +\tcode{ranges::reserve_hint(t)} is otherwise not required to be well-defined +after evaluating \tcode{ranges::\linebreak begin(t)}. +For example, +it is possible for \tcode{ranges::reserve_hint(t)} to be well-defined for +an \libconceptx{approximate\-ly_sized_range}{approximately_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} +\end{itemdescr} + \rSec2[range.sized]{Sized ranges} \pnum -The \libconcept{sized_range} concept refines \libconcept{range} with +The \libconcept{sized_range} concept +refines \libconcept{approximately_sized_range} with the requirement that the number of elements in the range can be determined in amortized constant time using \tcode{ranges::size}. \begin{itemdecl} template concept @\deflibconcept{sized_range}@ = - @\libconcept{range}@ && requires(T& t) { ranges::size(t); }; + @\libconcept{approximately_sized_range}@ && requires(T& t) { ranges::size(t); }; \end{itemdecl} \begin{itemdescr} @@ -1405,7 +1517,7 @@ \pnum \begin{note} -\tcode{disable_sized_range} allows use of range types with the library +\tcode{disable_sized_range} allows use of \libconcept{range} types with the library that satisfy but do not in fact model \libconcept{sized_range}. \end{note} \end{itemdescr} @@ -1426,7 +1538,7 @@ \begin{itemdescr} \pnum -\tcode{T} models \libconcept{view} only if: +\tcode{T} models \libconcept{view} only if \begin{itemize} \item \tcode{T} has \bigoh{1} move construction; and @@ -1502,8 +1614,8 @@ \remarks Pursuant to \ref{namespace.std}, users may specialize \tcode{enable_view} to \tcode{true} -for cv-unqualified program-defined types which model \libconcept{view}, -and \tcode{false} for types which do not. +for cv-unqualified program-defined types that model \libconcept{view}, +and \tcode{false} for types that do not. Such specializations shall be usable in constant expressions\iref{expr.const} and have type \tcode{const bool}. @@ -1620,7 +1732,7 @@ \rSec2[range.utility.helpers]{Helper concepts} \pnum -Many of the types in subclause~\ref{range.utility} are specified in terms of +Many of the types in \ref{range.utility} are specified in terms of the following exposition-only concepts: \begin{codeblock} @@ -1632,7 +1744,7 @@ template concept @\defexposconceptnc{has-arrow}@ = // \expos - @\libconcept{input_iterator}@ && (is_pointer_v || requires(I i) { i.operator->(); }); + @\libconcept{input_iterator}@ && (is_pointer_v || requires(const I i) { i.operator->(); }); template concept @\defexposconceptnc{different-from}@ = // \expos @@ -1850,17 +1962,17 @@ constexpr operator PairLike() const; constexpr I begin() const requires @\libconcept{copyable}@; - [[nodiscard]] constexpr I begin() requires (!@\libconcept{copyable}@); + constexpr I begin() requires (!@\libconcept{copyable}@); constexpr S end() const; constexpr bool empty() const; constexpr @\placeholdernc{make-unsigned-like-t}@> size() const requires (K == subrange_kind::sized); - [[nodiscard]] constexpr subrange next(iter_difference_t n = 1) const & + constexpr subrange next(iter_difference_t n = 1) const & requires @\libconcept{forward_iterator}@; - [[nodiscard]] constexpr subrange next(iter_difference_t n = 1) &&; - [[nodiscard]] constexpr subrange prev(iter_difference_t n = 1) const + constexpr subrange next(iter_difference_t n = 1) &&; + constexpr subrange prev(iter_difference_t n = 1) const requires @\libconcept{bidirectional_iterator}@; constexpr subrange& advance(iter_difference_t n); }; @@ -1979,7 +2091,7 @@ \indexlibrarymember{begin}{subrange}% \begin{itemdecl} -[[nodiscard]] constexpr I begin() requires (!@\libconcept{copyable}@); +constexpr I begin() requires (!@\libconcept{copyable}@); \end{itemdecl} \begin{itemdescr} @@ -2027,7 +2139,7 @@ \indexlibrarymember{next}{subrange}% \begin{itemdecl} -[[nodiscard]] constexpr subrange next(iter_difference_t n = 1) const & +constexpr subrange next(iter_difference_t n = 1) const & requires @\libconcept{forward_iterator}@; \end{itemdecl} @@ -2044,7 +2156,7 @@ \indexlibrarymember{next}{subrange}% \begin{itemdecl} -[[nodiscard]] constexpr subrange next(iter_difference_t n = 1) &&; +constexpr subrange next(iter_difference_t n = 1) &&; \end{itemdecl} \begin{itemdescr} @@ -2059,7 +2171,7 @@ \indexlibrarymember{prev}{subrange}% \begin{itemdecl} -[[nodiscard]] constexpr subrange prev(iter_difference_t n = 1) const +constexpr subrange prev(iter_difference_t n = 1) const requires @\libconcept{bidirectional_iterator}@; \end{itemdecl} @@ -2248,25 +2360,33 @@ \end{codeblock} \pnum -Let \exposid{container-insertable} be defined as follows: +Let \exposid{container-appendable} be defined as follows: \begin{codeblock} template -constexpr bool @\exposid{container-insertable}@ = // \expos +constexpr bool @\exposid{container-appendable}@ = // \expos requires(Container& c, Ref&& ref) { - requires (requires { c.push_back(std::forward(ref)); } || + requires (requires { c.emplace_back(std::forward(ref)); } || + requires { c.push_back(std::forward(ref)); } || + requires { c.emplace(c.end(), std::forward(ref)); } || requires { c.insert(c.end(), std::forward(ref)); }); }; \end{codeblock} \pnum -Let \exposid{container-inserter} be defined as follows: +Let \exposid{container-append} be defined as follows: \begin{codeblock} -template -constexpr auto @\exposid{container-inserter}@(Container& c) { // \expos - if constexpr (requires { c.push_back(declval()); }) - return back_inserter(c); - else - return inserter(c, c.end()); +template +constexpr auto @\exposid{container-append}@(Container& c) { // \expos + return [&c](Ref&& ref) { + if constexpr (requires { c.emplace_back(declval()); }) + c.emplace_back(std::forward(ref)); + else if constexpr (requires { c.push_back(declval()); }) + c.push_back(std::forward(ref)); + else if constexpr (requires { c.emplace(c.end(), declval()); }) + c.emplace(c.end(), std::forward(ref)); + else + c.insert(c.end(), std::forward(ref)); + }; } \end{codeblock} @@ -2328,13 +2448,13 @@ \item \tcode{\libconcept{constructible_from}} is \tcode{true}, and \item -\tcode{\exposid{container-insertable}>} is \tcode{true}: +\tcode{\exposid{container-appendable}>} is \tcode{true}: \end{itemize} \begin{codeblock} C c(std::forward(args)...); -if constexpr (@\libconcept{sized_range}@ && @\exposid{reservable-container}@) - c.reserve(static_cast>(ranges::size(r))); -ranges::copy(r, @\exposid{container-inserter}@>(c)); +if constexpr (@\libconcept{approximately_sized_range}@ && @\exposid{reservable-container}@) + c.reserve(static_cast>(ranges::reserve_hint(r))); +ranges::for_each(r, @\exposid{container-append}@(c)); \end{codeblock} \item Otherwise, the program is ill-formed. @@ -2344,7 +2464,7 @@ Otherwise, if \tcode{\libconcept{input_range}>} is \tcode{true}: \begin{codeblock} -to(r | views::transform([](auto&& elem) { +to(ref_view(r) | views::transform([](auto&& elem) { return to>(std::forward(elem)); }), std::forward(args)...); \end{codeblock} @@ -2533,6 +2653,7 @@ constexpr const T* begin() const noexcept; constexpr T* end() noexcept; constexpr const T* end() const noexcept; + static constexpr bool empty() noexcept; static constexpr size_t size() noexcept; constexpr T* data() noexcept; constexpr const T* data() const noexcept; @@ -2603,6 +2724,17 @@ Equivalent to: \tcode{return data() + 1;} \end{itemdescr} +\indexlibrarymember{empty}{single_view}% +\begin{itemdecl} +static constexpr bool empty() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return false;} +\end{itemdescr} + \indexlibrarymember{size}{single_view}% \begin{itemdecl} static constexpr size_t size() noexcept; @@ -2641,7 +2773,8 @@ Given subexpressions \tcode{E} and \tcode{F}, the expressions \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. +\tcode{iota_view>(E)} and \tcode{iota_view(E, F)}, +respectively. \pnum \begin{example} @@ -2685,6 +2818,7 @@ constexpr auto end() const; constexpr @\exposid{iterator}@ end() const requires @\libconcept{same_as}@; + constexpr bool empty() const; constexpr auto size() const requires @\seebelow@; }; @@ -2902,6 +3036,17 @@ Equivalent to: \tcode{return \exposid{iterator}\{\exposid{bound_}\};} \end{itemdescr} +\indexlibrarymember{empty}{iota_view}% +\begin{itemdecl} +constexpr bool empty() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{value_} == \exposid{bound_};} +\end{itemdescr} + \indexlibrarymember{size}{iota_view}% \begin{itemdecl} constexpr auto size() const requires @\seebelow@; @@ -2933,6 +3078,7 @@ \rSec3[range.iota.iterator]{Class \tcode{iota_view::\exposid{iterator}}} +\indexlibraryglobal{iota_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{weakly_incrementable}@ W, @\libconcept{semiregular}@ Bound> @@ -3313,6 +3459,7 @@ \rSec3[range.iota.sentinel]{Class \tcode{iota_view::\exposid{sentinel}}} +\indexlibraryglobal{iota_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{weakly_incrementable}@ W, @\libconcept{semiregular}@ Bound> @@ -3394,7 +3541,7 @@ Given subexpressions \tcode{E} and \tcode{F}, the expressions \tcode{views::repeat(E)} and \tcode{views::repeat(E, F)} are expression-equivalent to -\tcode{repeat_view(E)} and \tcode{repeat_view(E, F)}, respectively. +\tcode{repeat_view>(E)} and \tcode{repeat_view(E, F)}, respectively. \pnum \begin{example} @@ -3444,8 +3591,8 @@ constexpr auto size() const requires (!@\libconcept{same_as}@); }; - template - repeat_view(T, Bound) -> repeat_view; + template + repeat_view(T, Bound = Bound()) -> repeat_view; } \end{codeblock} @@ -3551,6 +3698,7 @@ \rSec3[range.repeat.iterator]{Class \tcode{repeat_view::\exposid{iterator}}} +\indexlibraryglobal{repeat_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{move_constructible}@ T, @\libconcept{semiregular}@ Bound> @@ -3854,7 +4002,7 @@ template concept @\defexposconceptnc{stream-extractable}@ = // \expos requires(basic_istream& is, Val& t) { - is >> t; + is >> t; }; template<@\libconcept{movable}@ Val, class CharT, class Traits = char_traits> @@ -3904,6 +4052,7 @@ \rSec3[range.istream.iterator]{Class \tcode{basic_istream_view::\exposid{iterator}}} +\indexlibraryglobal{basic_istream_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{movable}@ Val, class CharT, class Traits> @@ -4194,7 +4343,7 @@ \rSec2[range.nonprop.cache]{Non-propagating cache} \pnum -Some types in subclause \ref{range.adaptors} are specified in terms of +Some types in \ref{range.adaptors} are specified in terms of an exposition-only class template \exposid{non-propagating-\brk{}cache}. \tcode{\exposid{non-propagating-cache}} behaves exactly like \tcode{optional} with the following differences: @@ -4299,6 +4448,16 @@ constexpr T& @\exposid{as-lvalue}@(T&& t) { // \expos return static_cast(t); } + + template + concept @\defexposconceptnc{all-random-access}@ = // \expos + (@\libconcept{random_access_range}@<@\exposid{maybe-const}@> && ...); + template + concept @\defexposconceptnc{all-bidirectional}@ = // \expos + (@\libconcept{bidirectional_range}@<@\exposid{maybe-const}@> && ...); + template + concept @\defexposconceptnc{all-forward}@ = // \expos + (@\libconcept{forward_range}@<@\exposid{maybe-const}@> && ...); } \end{codeblock} @@ -4355,6 +4514,9 @@ constexpr auto size() const requires @\libconcept{sized_range}@ { return ranges::size(*@\exposid{r_}@); } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(*@\exposid{r_}@); } + constexpr auto data() const requires @\libconcept{contiguous_range}@ { return ranges::data(*@\exposid{r_}@); } }; @@ -4395,6 +4557,8 @@ \pnum \tcode{owning_view} is a move-only view of the elements of some other range. + +\indexlibraryglobal{owning_view}% \begin{codeblock} namespace std::ranges { template<@\libconcept{range}@ R> @@ -4433,6 +4597,11 @@ constexpr auto size() const requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{r_}@); } + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{r_}@); } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{r_}@); } + constexpr auto data() requires @\libconcept{contiguous_range}@ { return ranges::data(@\exposid{r_}@); } constexpr auto data() const requires @\libconcept{contiguous_range}@ @@ -4441,6 +4610,7 @@ } \end{codeblock} +\indexlibraryctor{owning_view}% \begin{itemdecl} constexpr owning_view(R&& t); \end{itemdecl} @@ -4470,7 +4640,9 @@ The expression \tcode{views::as_rvalue(E)} is expression-equivalent to: \begin{itemize} \item -\tcode{views::all(E)} if \tcode{\libconcept{same_as}, range_reference_t>} is \tcode{true}. +\tcode{views::all(E)} if +\tcode{T} models \libconcept{input_range} and +\tcode{\libconcept{same_as}, range_reference_t>} is \tcode{true}. \item Otherwise, \tcode{as_rvalue_view(E)}. \end{itemize} @@ -4523,6 +4695,11 @@ constexpr auto size() requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } constexpr auto size() const requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } }; template @@ -4658,6 +4835,7 @@ \rSec3[range.filter.iterator]{Class \tcode{filter_view::\exposid{iterator}}} +\indexlibraryglobal{filter_view::\exposid{iterator}}% \indexlibrarymember{iterator}{filter_view}% \begin{codeblock} namespace std::ranges { @@ -4912,6 +5090,7 @@ \rSec3[range.filter.sentinel]{Class \tcode{filter_view::\exposid{sentinel}}} +\indexlibraryglobal{filter_view::\exposid{sentinel}}% \indexlibrarymember{sentinel}{filter_view}% \begin{codeblock} namespace std::ranges { @@ -5038,6 +5217,11 @@ constexpr auto size() requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } constexpr auto size() const requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } }; template @@ -5149,6 +5333,7 @@ \rSec3[range.transform.iterator]{Class template \tcode{transform_view::\exposid{iterator}}} +\indexlibraryglobal{transform_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V, @\libconcept{move_constructible}@ F> @@ -5532,6 +5717,7 @@ \rSec3[range.transform.sentinel]{Class template \tcode{transform_view::\exposid{sentinel}}} +\indexlibraryglobal{transform_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V, @\libconcept{move_constructible}@ F> @@ -5828,6 +6014,22 @@ auto n = ranges::size(@\exposid{base_}@); return ranges::min(n, static_cast(@\exposid{count_}@)); } + + constexpr auto reserve_hint() { + if constexpr (@\libconcept{approximately_sized_range}@) { + auto n = static_cast>(ranges::reserve_hint(@\exposid{base_}@)); + return @\exposid{to-unsigned-like}@(ranges::min(n, @\exposid{count_}@)); + } + return @\exposid{to-unsigned-like}@(@\exposid{count_}@); + } + + constexpr auto reserve_hint() const { + if constexpr (@\libconcept{approximately_sized_range}@) { + auto n = static_cast>(ranges::reserve_hint(@\exposid{base_}@)); + return @\exposid{to-unsigned-like}@(ranges::min(n, @\exposid{count_}@)); + } + return @\exposid{to-unsigned-like}@(@\exposid{count_}@); + } }; template @@ -5854,6 +6056,7 @@ \rSec3[range.take.sentinel]{Class template \tcode{take_view::\exposid{sentinel}}} +\indexlibraryglobal{take_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{view}@ V> @@ -6039,6 +6242,7 @@ \rSec3[range.take.while.sentinel]{Class template \tcode{take_while_view::\exposid{sentinel}}} +\indexlibraryglobal{take_while_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{view}@ V, class Pred> @@ -6159,7 +6363,7 @@ \item Otherwise, if \tcode{T} is -a specialization of \tcode{subrange}\iref{range.subrange} +a specialization of \tcode{subrange} that models \libconcept{random_access_range} and \libconcept{sized_range}, then \tcode{T(ranges::begin(E) + std::min(ranges::distance(E), F), ranges::\linebreak{}end(E), @@ -6238,6 +6442,16 @@ return s < c ? 0 : s - c; } + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ { + const auto s = static_cast>(ranges::reserve_hint(@\exposid{base_}@)); + return @\exposid{to-unsigned-like}@(s < @\exposid{count_}@ ? 0 : s - @\exposid{count_}@); + } + + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ { + const auto s = static_cast>(ranges::reserve_hint(@\exposid{base_}@)); + return @\exposid{to-unsigned-like}@(s < @\exposid{count_}@ ? 0 : s - @\exposid{count_}@); + } + private: V @\exposid{base_}@ = V(); // \expos range_difference_t @\exposid{count_}@ = 0; // \expos @@ -6523,6 +6737,7 @@ \rSec3[range.join.iterator]{Class template \tcode{join_view::\exposid{iterator}}} +\indexlibraryglobal{join_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V> @@ -6623,7 +6838,7 @@ \exposid{Base} models \libconcept{forward_range}, and \tcode{range_reference_t<\exposid{Base}>} models \libconcept{forward_range}. In that case, -\tcode{iterator::iter\-ator_category} is defined as follows: +\tcode{\exposid{iterator}::iter\-ator_category} is defined as follows: \begin{itemize} \item Let \placeholder{OUTERC} denote \tcode{iterator_traits>::iterator_category}, and @@ -6643,7 +6858,7 @@ \end{itemize} \pnum -\tcode{iterator::difference_type} denotes the type: +\tcode{\exposid{iterator}::difference_type} denotes the type: \begin{codeblock} common_type_t< range_difference_t<@\exposid{Base}@>, @@ -6877,6 +7092,7 @@ \rSec3[range.join.sentinel]{Class template \tcode{join_view::\exposid{sentinel}}} +\indexlibraryglobal{join_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V> @@ -6926,7 +7142,6 @@ \end{itemdescr} \indexlibrarymember{operator==}{join_view::\exposid{sentinel}}%3431 - \begin{itemdecl} template requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> @@ -6971,21 +7186,16 @@ \rSec3[range.join.with.view]{Class template \tcode{join_with_view}} +\indexlibraryglobal{join_with_view}% \begin{codeblock} namespace std::ranges { - template - concept @\defexposconcept{compatible-joinable-ranges}@ = // \expos - @\libconcept{common_with}@, range_value_t

> && - @\libconcept{common_reference_with}@, range_reference_t

> && - @\libconcept{common_reference_with}@, range_rvalue_reference_t

>; - template concept @\defexposconcept{bidirectional-common}@ = @\libconcept{bidirectional_range}@ && @\libconcept{common_range}@; // \expos template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> requires @\libconcept{view}@ && @\libconcept{input_range}@> && @\libconcept{view}@ - && @\exposconcept{compatible-joinable-ranges}@, Pattern> + && @\exposconcept{concatable}@, Pattern> class join_with_view : public view_interface> { using @\exposid{InnerRng}@ = range_reference_t; // \expos @@ -7031,7 +7241,8 @@ requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ && is_reference_v> && - @\libconcept{input_range}@> { + @\libconcept{input_range}@> && + @\exposconcept{concatable}@, const Pattern> { return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; } @@ -7046,7 +7257,8 @@ constexpr auto end() const requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ && is_reference_v> && - @\libconcept{input_range}@> { + @\libconcept{input_range}@> && + @\exposconcept{concatable}@, const Pattern> { using InnerConstRng = range_reference_t; if constexpr (@\libconcept{forward_range}@ && @\libconcept{common_range}@ && @\libconcept{common_range}@) @@ -7065,6 +7277,7 @@ } \end{codeblock} +\indexlibraryctor{join_with_view}% \begin{itemdecl} constexpr explicit join_with_view(V base, Pattern pattern); \end{itemdecl} @@ -7076,6 +7289,7 @@ \exposid{pattern_} with \tcode{std::move(pattern)}. \end{itemdescr} +\indexlibraryctor{join_with_view}% \begin{itemdecl} template<@\libconcept{input_range}@ R> requires @\libconcept{constructible_from}@> && @@ -7092,11 +7306,12 @@ \rSec3[range.join.with.iterator]{Class template \tcode{join_with_view::\exposid{iterator}}} +\indexlibraryglobal{join_with_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> requires @\libconcept{view}@ && @\libconcept{input_range}@> - && @\libconcept{view}@ && @\exposconcept{compatible-joinable-ranges}@, Pattern> + && @\libconcept{view}@ && @\exposconcept{concatable}@, Pattern> template class join_with_view::@\exposid{iterator}@ { using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos @@ -7214,7 +7429,7 @@ \item Otherwise, if \placeholder{OUTERC}, \placeholder{INNERC}, and \placeholder{PATTERNC} -each model \tcode{\libconcept{derived_from}} +each model \tcode{\libconcept{derived_from}} and \exposid{InnerBase} and \exposid{PatternBase} each model \libconcept{common_range}, \tcode{iterator_cate\-gory} denotes \tcode{bidirectional_iterator_tag}. @@ -7237,9 +7452,9 @@ \tcode{\exposid{iterator}::difference_type} denotes the type: \begin{codeblock} common_type_t< - iter_difference_t<@\exposid{OuterIter}@>, - iter_difference_t<@\exposid{InnerIter}@>, - iter_difference_t<@\exposid{PatternIter}@>> + iter_difference_t<@\exposid{OuterIter}@>, + iter_difference_t<@\exposid{InnerIter}@>, + iter_difference_t<@\exposid{PatternIter}@>> \end{codeblock} \begin{itemdecl} @@ -7299,16 +7514,16 @@ if (@\exposid{inner_it_}@.index() == 0) { if (std::get<0>(@\exposid{inner_it_}@) != ranges::end(@\exposid{parent_}@->@\exposid{pattern_}@)) break; - @\exposid{inner_it_}@.emplace<1>(ranges::begin(@\exposid{update-inner}@())); + @\exposid{inner_it_}@.template emplace<1>(ranges::begin(@\exposid{update-inner}@())); } else { if (std::get<1>(@\exposid{inner_it_}@) != ranges::end(@\exposid{get-inner}@())) break; if (++@\exposid{outer}@() == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { if constexpr (@\exposid{ref-is-glvalue}@) - @\exposid{inner_it_}@.emplace<0>(); + @\exposid{inner_it_}@.template emplace<0>(); break; } - @\exposid{inner_it_}@.emplace<0>(ranges::begin(@\exposid{parent_}@->@\exposid{pattern_}@)); + @\exposid{inner_it_}@.template emplace<0>(ranges::begin(@\exposid{parent_}@->@\exposid{pattern_}@)); } } \end{codeblock} @@ -7335,7 +7550,7 @@ Then, equivalent to: \begin{codeblock} if (@\exposid{outer}@() != ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { - @\exposid{inner_it_}@.emplace<1>(ranges::begin(@\exposid{update-inner}@())); + @\exposid{inner_it_}@.template emplace<1>(ranges::begin(@\exposid{update-inner}@())); @\exposidnc{satisfy}@(); } \end{codeblock} @@ -7357,9 +7572,9 @@ Then, equivalent to: \begin{codeblock} if (i.@\exposid{inner_it_}@.index() == 0) - @\exposid{inner_it_}@.emplace<0>(std::get<0>(std::move(i.@\exposid{inner_it_}@))); + @\exposid{inner_it_}@.template emplace<0>(std::get<0>(std::move(i.@\exposid{inner_it_}@))); else - @\exposid{inner_it_}@.emplace<1>(std::get<1>(std::move(i.@\exposid{inner_it_}@))); + @\exposid{inner_it_}@.template emplace<1>(std::get<1>(std::move(i.@\exposid{inner_it_}@))); \end{codeblock} \pnum @@ -7369,6 +7584,7 @@ \end{note} \end{itemdescr} +\indexlibrarymember{operator--}{join_with_view::\exposid{iterator}}% \begin{itemdecl} constexpr decltype(auto) operator*() const; \end{itemdecl} @@ -7384,6 +7600,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{join_with_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -7399,6 +7616,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{join_with_view::\exposid{iterator}}% \begin{itemdecl} constexpr void operator++(int); \end{itemdecl} @@ -7409,6 +7627,7 @@ Equivalent to \tcode{++*this}. \end{itemdescr} +\indexlibrarymember{operator++}{join_with_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator++(int) requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_iterator}@<@\exposid{OuterIter}@> && @\libconcept{forward_iterator}@<@\exposid{InnerIter}@>; @@ -7425,6 +7644,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{join_with_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator--() requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && @@ -7438,7 +7658,7 @@ \begin{codeblock} if (@\exposid{outer_it_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { auto&& inner = *--@\exposid{outer_it_}@; - @\exposid{inner_it_}@.emplace<1>(ranges::end(inner)); + @\exposid{inner_it_}@.template emplace<1>(ranges::end(inner)); } while (true) { @@ -7446,7 +7666,7 @@ auto& it = std::get<0>(@\exposid{inner_it_}@); if (it == ranges::begin(@\exposid{parent_}@->@\exposid{pattern_}@)) { auto&& inner = *--@\exposid{outer_it_}@; - @\exposid{inner_it_}@.emplace<1>(ranges::end(inner)); + @\exposid{inner_it_}@.template emplace<1>(ranges::end(inner)); } else { break; } @@ -7454,7 +7674,7 @@ auto& it = std::get<1>(@\exposid{inner_it_}@); auto&& inner = *@\exposid{outer_it_}@; if (it == ranges::begin(inner)) { - @\exposid{inner_it_}@.emplace<0>(ranges::end(@\exposid{parent_}@->@\exposid{pattern_}@)); + @\exposid{inner_it_}@.template emplace<0>(ranges::end(@\exposid{parent_}@->@\exposid{pattern_}@)); } else { break; } @@ -7465,6 +7685,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{join_with_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator--(int) requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && @@ -7499,11 +7720,12 @@ \rSec3[range.join.with.sentinel]{Class template \tcode{join_with_view::\exposid{sentinel}}} +\indexlibraryglobal{join_with_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> requires @\libconcept{view}@ && @\libconcept{input_range}@> - && @\libconcept{view}@ && @\exposconcept{compatible-joinable-ranges}@, Pattern> + && @\libconcept{view}@ && @\exposconcept{concatable}@, Pattern> template class join_with_view::@\exposid{sentinel}@ { using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos @@ -7897,10 +8119,9 @@ private: @\exposid{outer-iterator}@ @\exposid{i_}@ = @\exposid{outer-iterator}@(); // \expos - public: - value_type() = default; - constexpr explicit value_type(@\exposid{outer-iterator}@ i); + constexpr explicit value_type(@\exposid{outer-iterator}@ i); // \expos + public: constexpr @\exposid{inner-iterator}@ begin() const; constexpr default_sentinel_t end() const noexcept; }; @@ -8150,6 +8371,7 @@ \rSec3[range.split.view]{Class template \tcode{split_view}} +\indexlibraryglobal{split_view} \begin{codeblock} namespace std::ranges { template<@\libconcept{forward_range}@ V, @\libconcept{forward_range}@ Pattern> @@ -8201,6 +8423,7 @@ } \end{codeblock} +\indexlibraryctor{split_view} \begin{itemdecl} constexpr explicit split_view(V base, Pattern pattern); \end{itemdecl} @@ -8227,6 +8450,7 @@ \exposid{pattern_} with \tcode{views::\linebreak single(std::move(e))}. \end{itemdescr} +\indexlibrarymember{begin}{split_view} \begin{itemdecl} constexpr @\exposid{iterator}@ begin(); \end{itemdecl} @@ -8264,6 +8488,7 @@ \rSec3[range.split.iterator]{Class \tcode{split_view::\exposid{iterator}}} +\indexlibraryglobal{split_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{forward_range}@ V, @\libconcept{forward_range}@ Pattern> @@ -8296,6 +8521,7 @@ } \end{codeblock} +\indexlibraryctor{split_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@(split_view& parent, iterator_t current, subrange> next); \end{itemdecl} @@ -8308,6 +8534,7 @@ \exposid{next_} with \tcode{std::move(next)}. \end{itemdescr} +\indexlibrarymember{base}{split_view::\exposid{iterator}}% \begin{itemdecl} constexpr iterator_t base() const; \end{itemdecl} @@ -8318,6 +8545,7 @@ Equivalent to: \tcode{return \exposid{cur_};} \end{itemdescr} +\indexlibrarymember{operator*}{split_view::\exposid{iterator}}% \begin{itemdecl} constexpr value_type operator*() const; \end{itemdecl} @@ -8328,6 +8556,7 @@ Equivalent to: \tcode{return \{\exposid{cur_}, \exposid{next_}.begin()\};} \end{itemdescr} +\indexlibrarymember{operator++}{split_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -8353,6 +8582,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{split_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} @@ -8368,6 +8598,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator==}{split_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} @@ -8383,6 +8614,7 @@ \rSec3[range.split.sentinel]{Class \tcode{split_view::\exposid{sentinel}}} +\indexlibraryglobal{split_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{forward_range}@ V, @\libconcept{forward_range}@ Pattern> @@ -8401,6 +8633,7 @@ } \end{codeblock} +\indexlibraryctor{split_view::\exposid{sentinel}}% \begin{itemdecl} constexpr explicit @\exposid{sentinel}@(split_view& parent); \end{itemdecl} @@ -8411,6 +8644,7 @@ Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. \end{itemdescr} +\indexlibrarymember{operator==}{split_view::\exposid{sentinel}}% \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} @@ -8421,658 +8655,634 @@ Equivalent to: \tcode{return x.\exposid{cur_} == y.\exposid{end_} \&\& !x.\exposid{trailing_empty_};} \end{itemdescr} -\rSec2[range.counted]{Counted view} - -\pnum -\indextext{range!counted}% -A counted view presents a view of the elements -of the counted range\iref{iterator.requirements.general} \countedrange{i}{n} -for an iterator \tcode{i} and non-negative integer \tcode{n}. - -\pnum -\indexlibrarymember{counted}{views}% -The name \tcode{views::counted} denotes -a customization point object\iref{customization.point.object}. -Let \tcode{E} and \tcode{F} be expressions, -let \tcode{T} be \tcode{decay_t}, and -let \tcode{D} be \tcode{iter_difference_t}. -If \tcode{decltype((F))} does not model -\tcode{\libconcept{convertible_to}}, -\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} -Otherwise, \tcode{views::counted(E, F)} -is expression-equivalent to: - -\begin{itemize} -\item -If \tcode{T} models \libconcept{contiguous_iterator}, -then \tcode{span(to_address(E), static_cast(static_-\linebreak{}cast(F)))}. - -\item -Otherwise, if \tcode{T} models \libconcept{random_access_iterator}, -then \tcode{subrange(E, E + static_cast(F))}, -except that \tcode{E} is evaluated only once. - -\item -Otherwise, -\tcode{subrange(counted_iterator(E, F), default_sentinel)}. -\end{itemize} +\rSec2[range.concat]{Concat view} -\rSec2[range.common]{Common view} - -\rSec3[range.common.overview]{Overview} - -\pnum -\tcode{common_view} takes a view which has different types for -its iterator and sentinel and turns it into a view of the same -elements with an iterator and sentinel of the same type. +\rSec3[range.concat.overview]{Overview} \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} +\tcode{concat_view} presents a view that concatenates all the underlying ranges. \pnum -\indexlibrarymember{common}{views}% -The name \tcode{views::common} denotes a -range adaptor object\iref{range.adaptor.object}. -Given a subexpression \tcode{E}, -the expression \tcode{views::common(E)} is expression-equivalent to: +The name \tcode{views::concat} denotes +a customization point object\iref{customization.point.object}. +Given a pack of subexpressions \tcode{Es...}, +the expression \tcode{views::concat(Es...)} 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\}}. +\item \tcode{views::all(Es...)} if \tcode{Es} is a pack with only one element +whose type models \libconcept{input_range}, +\item otherwise, \tcode{concat_view(Es...)}. \end{itemize} - -\pnum \begin{example} \begin{codeblock} -// Legacy algorithm: -template -size_t count(ForwardIterator first, ForwardIterator last); - -template<@\libconcept{forward_range}@ R> -void my_algo(R&& r) { - auto&& common = views::common(r); - auto cnt = count(common.begin(), common.end()); - // ... +vector v1{1, 2, 3}, v2{4, 5}, v3{}; +array a{6, 7, 8}; +auto s = views::single(9); +for (auto&& i : views::concat(v1, v2, v3, a, s)) { + print("{} ", i); // prints \tcode{1 2 3 4 5 6 7 8 9} } \end{codeblock} \end{example} -\rSec3[range.common.view]{Class template \tcode{common_view}} +\rSec3[range.concat.view]{Class template \tcode{concat_view}} -\indexlibraryglobal{common_view}% -\indexlibrarymember{base}{common_view}% -\indexlibrarymember{size}{common_view}% -\indexlibrarymember{begin}{common_view}% -\indexlibrarymember{end}{common_view}% +\indexlibraryglobal{concat_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V> - requires (!@\libconcept{common_range}@ && @\libconcept{copyable}@>) - class common_view : public view_interface> { - private: - V @\exposid{base_}@ = V(); // \expos + template + using @\exposidnc{concat-reference-t}@ = common_reference_t...>; // \expos + template + using @\exposidnc{concat-value-t}@ = common_type_t...>; // \expos + template + using @\exposidnc{concat-rvalue-reference-t}@ = // \expos + common_reference_t...>; - public: - common_view() requires @\libconcept{default_initializable}@ = default; + template + concept @\exposconcept{concat-indirectly-readable}@ = @\seebelow@; // \expos + template + concept @\exposconcept{concatable}@ = @\seebelow@; // \expos + template + concept @\exposconcept{concat-is-random-access}@ = @\seebelow@; // \expos + template + concept @\exposconcept{concat-is-bidirectional}@ = @\seebelow@; // \expos - constexpr explicit common_view(V r); + template<@\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && + @\exposconcept{concatable}@ + class concat_view : public view_interface> { - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + tuple @\exposidnc{views_}@; // \expos - constexpr auto begin() { - if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) - return ranges::begin(@\exposid{base_}@); - else - return common_iterator, sentinel_t>(ranges::begin(@\exposid{base_}@)); - } + // \ref{range.concat.iterator}, class template \tcode{concat_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos - constexpr auto begin() const requires @\libconcept{range}@ { - if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) - return ranges::begin(@\exposid{base_}@); - else - return common_iterator, sentinel_t>(ranges::begin(@\exposid{base_}@)); - } + public: + constexpr concat_view() = default; + constexpr explicit concat_view(Views... views); - constexpr auto end() { - if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) - return ranges::begin(@\exposid{base_}@) + ranges::distance(@\exposid{base_}@); - else - return common_iterator, sentinel_t>(ranges::end(@\exposid{base_}@)); - } + constexpr @\exposid{iterator}@ begin() requires (!(@\exposconcept{simple-view}@ && ...)); + constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{range}@ && ...) && @\exposconcept{concatable}@; - constexpr auto end() const requires @\libconcept{range}@ { - if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) - return ranges::begin(@\exposid{base_}@) + ranges::distance(@\exposid{base_}@); - else - return common_iterator, sentinel_t>(ranges::end(@\exposid{base_}@)); - } + constexpr auto end() requires (!(@\exposconcept{simple-view}@ && ...)); + constexpr auto end() const + requires (@\libconcept{range}@ && ...) && @\exposconcept{concatable}@; - constexpr auto size() requires @\libconcept{sized_range}@ { - return ranges::size(@\exposid{base_}@); - } - constexpr auto size() const requires @\libconcept{sized_range}@ { - return ranges::size(@\exposid{base_}@); - } + constexpr auto size() requires (@\libconcept{sized_range}@ && ...); + constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); }; - template - common_view(R&&) -> common_view>; + template + concat_view(R&&...) -> concat_view...>; } \end{codeblock} -\indexlibraryctor{common_view}% \begin{itemdecl} -constexpr explicit common_view(V base); +template + concept @\defexposconcept{concat-indirectly-readable}@ = @\seebelow@; // \expos \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)}. -\end{itemdescr} - -\rSec2[range.reverse]{Reverse view} +The exposition-only \exposconcept{concat-indirectly-readable} concept +is equivalent to: +\begin{codeblock} +template + concept @\defexposconcept{concat-indirectly-readable-impl}@ = // \expos + requires (const It it) { + { *it } -> @\libconcept{convertible_to}@; + { ranges::iter_move(it) } -> @\libconcept{convertible_to}@; + }; -\rSec3[range.reverse.overview]{Overview} +template + concept @\exposconcept{concat-indirectly-readable}@ = // \expos + @\libconcept{common_reference_with}@<@\exposid{concat-reference-t}@&&, + @\exposid{concat-value-t}@&> && + @\libconcept{common_reference_with}@<@\exposid{concat-reference-t}@&&, + @\exposid{concat-rvalue-reference-t}@&&> && + @\libconcept{common_reference_with}@<@\exposid{concat-rvalue-reference-t}@&&, + @\exposid{concat-value-t}@ const&> && + (@\exposconcept{concat-indirectly-readable-impl}@<@\exposid{concat-reference-t}@, + @\exposid{concat-rvalue-reference-t}@, + iterator_t> && ...); +\end{codeblock} +\end{itemdescr} -\pnum -\tcode{reverse_view} takes a bidirectional view and produces -another view that iterates the same elements in reverse order. +\begin{itemdecl} +template + concept @\defexposconcept{concatable}@ = @\seebelow@; // \expos +\end{itemdecl} +\begin{itemdescr} \pnum -\indexlibrarymember{reverse}{views}% -The name \tcode{views::reverse} denotes a -range adaptor object\iref{range.adaptor.object}. -Given a 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{} \tcode{subrange, reverse_iterator, K>} - 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: +The exposition-only \exposconcept{concatable} concept is equivalent to: \begin{codeblock} -subrange(E.end().base(), E.begin().base()) +template + concept @\exposconcept{concatable}@ = requires { // \expos + typename @\exposid{concat-reference-t}@; + typename @\exposid{concat-value-t}@; + typename @\exposid{concat-rvalue-reference-t}@; + } && @\exposconcept{concat-indirectly-readable}@; \end{codeblock} - \end{itemize} - However, in either case \tcode{E} is evaluated only once. -\item - Otherwise, equivalent to \tcode{reverse_view\{E\}}. -\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + concept @\defexposconcept{concat-is-random-access}@ = @\seebelow@; // \expos +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{example} +Let \tcode{Fs} be the pack that consists of all elements of \tcode{Rs} +except the last element, +then \exposconceptx{concat-is-ran\-dom-access}{concat-is-random-access} +is equivalent to: \begin{codeblock} -vector is {0,1,2,3,4}; -for (int i : is | views::reverse) - cout << i << ' '; // prints \tcode{4 3 2 1 0} +template + concept @\exposconcept{concat-is-random-access}@ = // \expos + @\exposconcept{all-random-access}@ && + (@\libconcept{common_range}@<@\exposid{maybe-const}@> && ...); \end{codeblock} -\end{example} +\end{itemdescr} -\rSec3[range.reverse.view]{Class template \tcode{reverse_view}} +\begin{itemdecl} +template + concept @\defexposconcept{concat-is-bidirectional}@ = @\seebelow@; // \expos +\end{itemdecl} -\indexlibraryglobal{reverse_view}% -\indexlibrarymember{base}{reverse_view}% -\indexlibrarymember{size}{reverse_view}% +\begin{itemdescr} +\pnum +Let \tcode{Fs} be the pack that consists of all elements of \tcode{Rs} +except the last element, +then \exposconceptx{concat-is-bidirec\-tional}{concat-is-bidirectional} +is equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{bidirectional_range}@ - class reverse_view : public view_interface> { - private: - V @\exposid{base_}@ = V(); // \expos - - public: - reverse_view() requires @\libconcept{default_initializable}@ = default; - - constexpr explicit reverse_view(V r); - - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } - - constexpr reverse_iterator> begin(); - constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; - constexpr auto begin() const requires @\libconcept{common_range}@; - - constexpr reverse_iterator> end(); - constexpr auto end() const requires @\libconcept{common_range}@; - - constexpr auto size() requires @\libconcept{sized_range}@ { - return ranges::size(@\exposid{base_}@); - } - - constexpr auto size() const requires @\libconcept{sized_range}@ { - return ranges::size(@\exposid{base_}@); - } - }; - - template - reverse_view(R&&) -> reverse_view>; -} +template + concept @\exposconcept{concat-is-bidirectional}@ = // \expos + @\exposconcept{all-bidirectional}@ && + (@\libconcept{common_range}@<@\exposid{maybe-const}@> && ...); \end{codeblock} +\end{itemdescr} -\indexlibraryctor{reverse_view}% +\indexlibraryctor{concat_view}% \begin{itemdecl} -constexpr explicit reverse_view(V base); +constexpr explicit concat_view(Views... views); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)}. +Initializes \exposid{views_} with \tcode{std::move(views)...}. \end{itemdescr} -\indexlibrarymember{begin}{reverse_view}% +\indexlibrarymember{begin}{concat_view}% \begin{itemdecl} -constexpr reverse_iterator> begin(); +constexpr @\exposid{iterator}@ begin() requires (!(@\exposconcept{simple-view}@ && ...)); +constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{range}@ && ...) && @\exposconcept{concatable}@; \end{itemdecl} \begin{itemdescr} \pnum -\returns +\effects +Let \exposid{is-const} be +\tcode{true} for the const-qualified overload, and +\tcode{false} otherwise. +Equivalent to: \begin{codeblock} -make_reverse_iterator(ranges::next(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@))) +@\exposid{iterator}@<@\exposid{is-const}@> it(this, in_place_index<0>, ranges::begin(std::get<0>(@\exposid{views_}@))); +it.template @\exposid{satisfy}@<0>(); +return it; \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} -\indexlibrarymember{begin}{reverse_view}% +\indexlibrarymember{end}{concat_view}% \begin{itemdecl} -constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; -constexpr auto begin() const requires @\libconcept{common_range}@; +constexpr auto end() requires (!(@\exposconcept{simple-view}@ && ...)); +constexpr auto end() const + requires (@\libconcept{range}@ && ...) && @\exposconcept{concatable}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return make_reverse_iterator(ranges::end(\exposid{base_}));} +Let \exposid{is-const} be +\tcode{true} for the const-qualified overload, and +\tcode{false} otherwise. +Equivalent to: +\begin{codeblock} +constexpr auto N = sizeof...(Views); +if constexpr (@\libconcept{common_range}@<@\exposid{maybe-const}@<@\exposid{is-const}@, Views...[N - 1]>>) { + return @\exposid{iterator}@<@\exposid{is-const}@>(this, in_place_index, + ranges::end(std::get(@\exposid{views_}@))); +} else { + return default_sentinel; +} +\end{codeblock} \end{itemdescr} -\indexlibrarymember{end}{reverse_view}% +\indexlibrarymember{size}{concat_view}% \begin{itemdecl} -constexpr reverse_iterator> end(); -constexpr auto end() const requires @\libconcept{common_range}@; +constexpr auto size() requires (@\libconcept{sized_range}@ && ...); +constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return make_reverse_iterator(ranges::begin(\exposid{base_}));} +Equivalent to: +\begin{codeblock} +return apply( + [](auto... sizes) { + using CT = @\exposid{make-unsigned-like-t}@>; + return (CT(sizes) + ...); + }, + @\exposid{tuple-transform}@(ranges::size, @\exposid{views_}@)); +\end{codeblock} \end{itemdescr} -\rSec2[range.as.const]{As const view} +\rSec3[range.concat.iterator]{Class \tcode{concat_view::\exposid{iterator}}} -\rSec3[range.as.const.overview]{Overview} +\indexlibrarymember{iterator}{concat_view}% +\indexlibraryglobal{concat_view::\exposid{iterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && + @\exposconcept{concatable}@ + template + class concat_view::@\exposid{iterator}@ { -\pnum -\tcode{as_const_view} presents a view of an underlying sequence as constant. -That is, the elements of an \tcode{as_const_view} cannot be modified. + public: + using iterator_category = @\seebelow@; // not always present + using iterator_concept = @\seebelow@; + using value_type = @\exposid{concat-value-t}@<@\exposid{maybe-const}@...>; + using difference_type = common_type_t>...>; -\pnum -The name \tcode{views::as_const} denotes -a range adaptor object\iref{range.adaptor.object}. -Let \tcode{E} be an expression, -let \tcode{T} be \tcode{decltype((E))}, and -let \tcode{U} be \tcode{remove_cvref_t}. -The expression \tcode{views::as_const(E)} is expression-equivalent to: -\begin{itemize} -\item -If \tcode{views::all_t} models \libconcept{constant_range}, -then \tcode{views::all(E)}. -\item -Otherwise, -if \tcode{U} denotes \tcode{empty_view} -for some type \tcode{X}, then \tcode{auto(views::empty)}. -\item -Otherwise, -if \tcode{U} denotes \tcode{span} -for some type \tcode{X} and some extent \tcode{Extent}, -then \tcode{span(E)}. -\item -Otherwise, -if \tcode{U} denotes \tcode{ref_view} for some type \tcode{X} and -\tcode{const X} models \libconcept{constant_range}, -then \tcode{ref_view(static_cast(E.base()))}. -\item -Otherwise, -if \tcode{E} is an lvalue, -\tcode{const U} models \libconcept{constant_range}, and -\tcode{U} does not model \libconcept{view}, -then \tcode{ref_view(static_cast(E))}. -\item -Otherwise, \tcode{as_const_view(E)}. -\end{itemize} + private: + using @\exposid{base-iter}@ = // \expos + variant>...>; -\pnum -\begin{example} -\begin{codeblock} -template<@\libconcept{constant_range}@ R> -void cant_touch_this(R&&); + @\exposid{maybe-const}@* @\exposid{parent_}@ = nullptr; // \expos + @\exposid{base-iter}@ @\exposid{it_}@; // \expos -vector hammer = {'m', 'c'}; -span beat = hammer; -cant_touch_this(views::as_const(beat)); // will not modify the elements of \tcode{hammer} -\end{codeblock} -\end{example} + template + constexpr void @\exposid{satisfy}@(); // \expos + template + constexpr void @\exposid{prev}@(); // \expos -\rSec3[range.as.const.view]{Class template \tcode{as_const_view}} + template + constexpr void @\exposid{advance-fwd}@(difference_type offset, // \expos + difference_type steps); + template + constexpr void @\exposid{advance-bwd}@(difference_type offset, // \expos + difference_type steps); -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{input_range}@ - class as_const_view : public view_interface> { - V @\exposid{base_}@ = V(); // \expos + template + constexpr explicit @\exposid{iterator}@(@\exposid{maybe-const}@* parent, // \expos + Args&&... args) + requires @\libconcept{constructible_from}@<@\exposid{base-iter}@, Args&&...>; public: - as_const_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit as_const_view(V base); - - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + @\exposid{iterator}@() = default; - constexpr auto begin() requires (!@\exposconcept{simple-view}@) { return ranges::cbegin(@\exposid{base_}@); } - constexpr auto begin() const requires @\libconcept{range}@ { return ranges::cbegin(@\exposid{base_}@); } + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && (@\libconcept{convertible_to}@, iterator_t> && ...); - constexpr auto end() requires (!@\exposconcept{simple-view}@) { return ranges::cend(@\exposid{base_}@); } - constexpr auto end() const requires @\libconcept{range}@ { return ranges::cend(@\exposid{base_}@); } + constexpr decltype(auto) operator*() const; + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) + requires @\exposconcept{all-forward}@; + constexpr @\exposid{iterator}@& operator--() + requires @\exposconcept{concat-is-bidirectional}@; + constexpr @\exposid{iterator}@ operator--(int) + requires @\exposconcept{concat-is-bidirectional}@; + constexpr @\exposid{iterator}@& operator+=(difference_type n) + requires @\exposconcept{concat-is-random-access}@; + constexpr @\exposid{iterator}@& operator-=(difference_type n) + requires @\exposconcept{concat-is-random-access}@; + constexpr decltype(auto) operator[](difference_type n) const + requires @\exposconcept{concat-is-random-access}@; - constexpr auto size() requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } - constexpr auto size() const requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{equality_comparable}@>> && ...); + friend constexpr bool operator==(const @\exposid{iterator}@& it, default_sentinel_t); + friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; + friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; + friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; + friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\exposconcept{all-random-access}@ && + (@\libconcept{three_way_comparable}@>> && ...)); + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& it, difference_type n) + requires @\exposconcept{concat-is-random-access}@; + friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& it) + requires @\exposconcept{concat-is-random-access}@; + friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& it, difference_type n) + requires @\exposconcept{concat-is-random-access}@; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{concat-is-random-access}@; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t) + requires @\seebelow@; + friend constexpr difference_type operator-(default_sentinel_t, const @\exposid{iterator}@& x) + requires @\seebelow@; + friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& it) noexcept(@\seebelow@); + friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept(@\seebelow@) + requires @\seebelow@; }; - - template - as_const_view(R&&) -> as_const_view>; } \end{codeblock} -\begin{itemdecl} -constexpr explicit as_const_view(V base); -\end{itemdecl} +\pnum +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +\begin{itemize} +\item +If +\tcode{\exposconcept{concat-is-random-access}} is modeled, +then \tcode{iterator_concept} denotes \tcode{ran\-dom_access_iterator_tag}. +\item +Otherwise, if +\tcode{\exposconcept{concat-is-bidirectional}} is modeled, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, if +\tcode{\exposconcept{all-forward}} is modeled, +then \tcode{iterator_concept} denotes \tcode{for\-ward_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} -\begin{itemdescr} \pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)}. -\end{itemdescr} +The member \grammarterm{typedef-name} \tcode{iterator_category} is defined +if and only if +\tcode{\exposconcept{all-forward}} is modeled. +In that case, +\tcode{\exposid{iterator}::iterator_category} is defined as follows: -\rSec2[range.elements]{Elements view} +\begin{itemize} +\item +If +\tcode{is_reference_v<\exposid{concat-reference-t}<\exposid{maybe-const}...>>} +is \tcode{false}, +then \tcode{iter\-ator_category} denotes \tcode{input_iterator_tag}. -\rSec3[range.elements.overview]{Overview} +\item +Otherwise, +let \tcode{Cs} denote the pack of types +\tcode{iterator_traits>>::iterator_category...}. +\begin{itemize} +\item +If +\tcode{(\libconcept{derived_from} \&\& ...) \&\& \exposconceptx{concat-is-random-ac-\linebreak{}cess}{concat-is-random-access}} +is \tcode{true}, +\tcode{iterator_category} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, if +\tcode{(\libconcept{derived_from} \&\& ...) \&\& \exposconceptx{concat-is-\linebreak{}bidirectional}{concat-is-bidirectional}} +is \tcode{true}, +\tcode{iterator_category} denotes \tcode{bidirectional_iter\-ator_tag}. +\item +Otherwise, if +\tcode{(\libconcept{derived_from} \&\& ...)} +is \tcode{true}, +\tcode{iterator_cate\-gory} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\end{itemize} +\end{itemize} -\pnum -\tcode{elements_view} takes -a view of tuple-like values and a \tcode{size_t}, and -produces a view with a value-type of the $N^\text{th}$ element -of the adapted view's value-type. +\indexlibrarymember{\exposid{satisfy}}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +template + constexpr void @\exposid{satisfy}@(); +\end{itemdecl} +\begin{itemdescr} \pnum -\indexlibrarymember{elements}{views}% -The name \tcode{views::elements} denotes -a range adaptor object\iref{range.adaptor.object}. -Given a subexpression \tcode{E} and constant expression \tcode{N}, -the expression \tcode{views::elements(E)} is expression-equivalent to -\tcode{elements_view, N>\{E\}}. - -\begin{example} +\effects +Equivalent to: \begin{codeblock} -auto historical_figures = map{ - pair{"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 } +if constexpr (N < (sizeof...(Views) - 1)) { + if (std::get(@\exposid{it_}@) == ranges::end(std::get(@\exposid{parent_}@->@\exposid{views_}@))) { + @\exposid{it_}@.template emplace(ranges::begin(std::get(@\exposid{parent_}@->@\exposid{views_}@))); + @\exposid{satisfy}@(); + } } \end{codeblock} -\end{example} +\end{itemdescr} -\pnum -\tcode{keys_view} is an alias for \tcode{elements_view}, and -is useful for extracting keys from associative containers. +\indexlibrarymember{\exposid{prev}}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +template + constexpr void @\exposid{prev}@(); +\end{itemdecl} -\begin{example} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -auto names = historical_figures | views::keys; -for (auto&& name : names) { - cout << name << ' '; // prints \tcode{Babbage Hamilton Lovelace Turing } +if constexpr (N == 0) { + --std::get<0>(@\exposid{it_}@); +} else { + if (std::get(@\exposid{it_}@) == ranges::begin(std::get(@\exposid{parent_}@->@\exposid{views_}@))) { + @\exposid{it_}@.template emplace(ranges::end(std::get(@\exposid{parent_}@->@\exposid{views_}@))); + @\exposid{prev}@(); + } else { + --std::get(@\exposid{it_}@); + } } \end{codeblock} -\end{example} +\end{itemdescr} -\pnum -\tcode{values_view} is an alias for \tcode{elements_view}, and -is useful for extracting values from associative containers. +\indexlibrarymember{\exposid{advance-fwd}}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +template + constexpr void @\exposid{advance-fwd}@(difference_type offset, difference_type steps); +\end{itemdecl} -\begin{example} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -auto is_even = [](const auto x) { return x % 2 == 0; }; -cout << ranges::count_if(historical_figures | views::values, is_even); // prints \tcode{2} +using underlying_diff_type = iter_difference_t>; +if constexpr (N == sizeof...(Views) - 1) { + std::get(@\exposid{it_}@) += static_cast(steps); +} else { + auto n_size = ranges::distance(std::get(@\exposid{parent_}@->@\exposid{views_}@)); + if (offset + steps < n_size) { + std::get(@\exposid{it_}@) += static_cast(steps); + } else { + @\exposid{it_}@.template emplace(ranges::begin(std::get(@\exposid{parent_}@->@\exposid{views_}@))); + @\exposid{advance-fwd}@(0, offset + steps - n_size); + } +} \end{codeblock} -\end{example} +\end{itemdescr} -\rSec3[range.elements.view]{Class template \tcode{elements_view}} +\indexlibrarymember{\exposid{advance-bwd}}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +template + constexpr void @\exposid{advance-bwd}@(difference_type offset, difference_type steps); +\end{itemdecl} -\indexlibraryglobal{elements_view}% -\indexlibrarymember{base}{elements_view}% -\indexlibrarymember{begin}{elements_view}% -\indexlibrarymember{end}{elements_view}% -\indexlibrarymember{size}{elements_view}% +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template - concept @\defexposconcept{has-tuple-element}@ = // \expos - @\exposconcept{tuple-like}@ && N < tuple_size_v; - - template - concept @\defexposconcept{returnable-element}@ = // \expos - is_reference_v || @\libconcept{move_constructible}@>; - - template<@\libconcept{input_range}@ V, size_t N> - requires @\libconcept{view}@ && @\exposconcept{has-tuple-element}@, N> && - @\exposconcept{has-tuple-element}@>, N> && - @\exposconcept{returnable-element}@, N> - class elements_view : public view_interface> { - public: - elements_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit elements_view(V base); - - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } +using underlying_diff_type = iter_difference_t>; +if constexpr (N == 0) { + std::get(@\exposid{it_}@) -= static_cast(steps); +} else { + if (offset >= steps) { + std::get(@\exposid{it_}@) -= static_cast(steps); + } else { + auto prev_size = ranges::distance(std::get(@\exposid{parent_}@->@\exposid{views_}@)); + @\exposid{it_}@.template emplace(ranges::end(std::get(@\exposid{parent_}@->@\exposid{views_}@))); + @\exposid{advance-bwd}@(prev_size, steps - offset); + } +} +\end{codeblock} +\end{itemdescr} - constexpr auto begin() requires (!@\exposconcept{simple-view}@) - { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@)); } +\indexlibraryctor{concat_view::\exposid{iterator}}% +\begin{itemdecl} +template + constexpr explicit @\exposid{iterator}@(@\exposid{maybe-const}@* parent, + Args&&... args) + requires @\libconcept{constructible_from}@<@\exposid{base-iter}@, Args&&...>; +\end{itemdecl} - constexpr auto begin() const requires @\libconcept{range}@ - { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@)); } +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{parent_} with \tcode{parent}, and +initializes \exposid{it_} with \tcode{std::forward(args)...}. +\end{itemdescr} - constexpr auto end() requires (!@\exposconcept{simple-view}@ && !@\libconcept{common_range}@) - { return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; } +\indexlibraryctor{concat_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{iterator}@ it) + requires Const && + (@\libconcept{convertible_to}@, iterator_t> && ...); +\end{itemdecl} - constexpr auto end() requires (!@\exposconcept{simple-view}@ && @\libconcept{common_range}@) - { return @\exposid{iterator}@{ranges::end(@\exposid{base_}@)}; } +\begin{itemdescr} +\pnum +\expects +\tcode{it.\exposid{it_}.valueless_by_exception()} is \tcode{false}. - constexpr auto end() const requires @\libconcept{range}@ - { return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; } +\pnum +\effects +Initializes \exposid{parent_} with \tcode{it.\exposid{parent_}}, and +let \tcode{$i$} be \tcode{it.\exposid{it_}.index()}, +initializes \exposid{it_} with +\tcode{\exposid{base-iter}(in_place_index<$i$>, std::get<$i$>(std::move(it.\exposid{it_})))}. +\end{itemdescr} - constexpr auto end() const requires @\libconcept{common_range}@ - { return @\exposid{iterator}@{ranges::end(@\exposid{base_}@)}; } +\indexlibrarymember{operator*}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr decltype(auto) operator*() const; +\end{itemdecl} - constexpr auto size() requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{base_}@); } +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{it_}.valueless_by_exception()} is \tcode{false}. - constexpr auto size() const requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{base_}@); } +\pnum +\effects +Equivalent to: +\begin{codeblock} +using reference = @\exposid{concat-reference-t}@<@\exposid{maybe-const}@...>; +return std::visit([](auto&& it) -> reference { return *it; }, + @\exposid{it_}@); +\end{codeblock} +\end{itemdescr} - private: - // \ref{range.elements.iterator}, class template \tcode{elements_view::\exposid{iterator}} - template class @\exposid{iterator}@; // \expos +\indexlibrarymember{operator++}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} - // \ref{range.elements.sentinel}, class template \tcode{elements_view::\exposid{sentinel}} - template class @\exposid{sentinel}@; // \expos +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{it_}.valueless_by_exception()} is \tcode{false}. - V @\exposid{base_}@ = V(); // \expos - }; -} +\pnum +\effects +Let \tcode{$i$} be \tcode{\exposid{it_}.index()}. +Equivalent to: +\begin{codeblock} +++std::get<@$i$@>(@\exposid{it_}@); +@\exposid{satisfy}@<@$i$@>(); +return *this; \end{codeblock} +\end{itemdescr} -\indexlibraryctor{elements_view}% +\indexlibrarymember{operator++}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit elements_view(V base); +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)}. +Equivalent to: +\begin{codeblock} +++*this; +\end{codeblock} \end{itemdescr} -\rSec3[range.elements.iterator]{Class template \tcode{elements_view::\exposid{iterator}}} +\indexlibrarymember{operator++}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) + requires @\exposconcept{all-forward}@; +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V, size_t N> - requires @\libconcept{view}@ && @\exposconcept{has-tuple-element}@, N> && - @\exposconcept{has-tuple-element}@>, N> && - @\exposconcept{returnable-element}@, N> - template - class elements_view::@\exposid{iterator}@ { - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} - iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos +\indexlibrarymember{operator--}{concat_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() + requires @\exposconcept{concat-is-bidirectional}@; +\end{itemdecl} - static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); // \expos +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{it_}.valueless_by_exception()} is \tcode{false}. - public: - using iterator_concept = @\seebelow@; - using iterator_category = @\seebelow@; // not always present - using value_type = remove_cvref_t>>; - using difference_type = range_difference_t<@\exposid{Base}@>; - - @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; - constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; - - constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; - constexpr iterator_t<@\exposid{Base}@> base() &&; - - constexpr decltype(auto) operator*() const - { return @\exposid{get-element}@(@\exposid{current_}@); } - - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; - - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - - constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - - constexpr decltype(auto) operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@> - { return @\exposid{get-element}@(@\exposid{current_}@ + n); } - - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; - - friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; - - friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; - }; -} -\end{codeblock} - -\pnum -The member \grammarterm{typedef-name} \tcode{iterator_concept} -is defined as follows: -\begin{itemize} -\item -If \exposid{Base} models \libconcept{random_access_range}, -then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. -\item -Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item -Otherwise, if \exposid{Base} models \libconcept{forward_range}, -then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. -\item -Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. -\end{itemize} - -\pnum -The member \grammarterm{typedef-name} \tcode{iterator_category} is defined -if and only if \exposid{Base} models \libconcept{forward_range}. -In that case, \tcode{iterator_category} is defined as follows: -Let \tcode{C} denote the type -\tcode{iterator_traits>::iterator_category}. -\begin{itemize} -\item -If \tcode{std::get(*\exposid{current_})} is an rvalue, -\tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\item -Otherwise, if \tcode{C} models \tcode{\libconcept{derived_from}}, -\tcode{iterator_category} denotes \tcode{random_access_iterator_tag}. -\item -Otherwise, \tcode{iterator_category} denotes \tcode{C}. -\end{itemize} +\pnum +\effects +Let \tcode{$i$} be \tcode{\exposid{it_}.index()}. +Equivalent to: +\begin{codeblock} +@\exposid{prev}@<@$i$@>(); +return *this; +\end{codeblock} +\end{itemdescr} +\indexlibrarymember{operator--}{concat_view::\exposid{iterator}}% \begin{itemdecl} -static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); +constexpr @\exposid{iterator}@ operator--(int) + requires @\exposconcept{concat-is-bidirectional}@; \end{itemdecl} \begin{itemdescr} @@ -9080,105 +9290,144 @@ \effects Equivalent to: \begin{codeblock} -if constexpr (is_reference_v>) { - return std::get(*i); -} else { - using E = remove_cv_t>>; - return static_cast(std::get(*i)); -} +auto tmp = *this; +--*this; +return tmp; \end{codeblock} \end{itemdescr} -\indexlibraryctor{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator+=}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); +constexpr @\exposid{iterator}@& operator+=(difference_type n) + requires @\exposconcept{concat-is-random-access}@; \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{\exposid{it_}.valueless_by_exception()} is \tcode{false}. + \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(current)}. +Let \tcode{$i$} be \tcode{\exposid{it_}.index()}. +Equivalent to: +\begin{codeblock} +if (n > 0) { + @\exposid{advance-fwd}@<@$i$@>(std::get<@$i$@>(@\exposid{it_}@) - ranges::begin(std::get<@$i$@>(@\exposid{parent_}@->@\exposid{views_}@)), n); +} else if (n < 0) { + @\exposid{advance-bwd}@<@$i$@>(std::get<@$i$@>(@\exposid{it_}@) - ranges::begin(std::get<@$i$@>(@\exposid{parent_}@->@\exposid{views_}@)), -n); +} +return *this; +\end{codeblock} \end{itemdescr} -\indexlibraryctor{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator-=}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@& operator-=(difference_type n) + requires @\exposconcept{concat-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +Equivalent to: +\begin{codeblock} +*this += -n; +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator[]}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +constexpr decltype(auto) operator[](difference_type n) const + requires @\exposconcept{concat-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{current_};} +Equivalent to: +\begin{codeblock} +return *((*this) + n); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator==}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() &&; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{equality_comparable}@>> && ...); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{x.\exposid{it_}.valueless_by_exception()} and +\tcode{y.\exposid{it_}.valueless_by_exception()} are each \tcode{false}. + \pnum \effects -Equivalent to: \tcode{return std::move(\exposid{current_});} +Equivalent to: +\begin{codeblock} +return x.@\exposid{it_}@ == y.@\exposid{it_}@; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator==}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +friend constexpr bool operator==(const @\exposid{iterator}@& it, default_sentinel_t); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{it.\exposid{it_}.valueless_by_exception()} is \tcode{false}. + \pnum \effects Equivalent to: \begin{codeblock} -++@\exposid{current_}@; -return *this; +constexpr auto last_idx = sizeof...(Views) - 1; +return it.@\exposid{it_}@.index() == last_idx && + std::get(it.@\exposid{it_}@) == ranges::end(std::get(it.@\exposid{parent_}@->@\exposid{views_}@)); \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator<}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr void operator++(int); +friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; +friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; +friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; +friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\exposconcept{all-random-access}@ && + (@\libconcept{three_way_comparable}@>> && ...)); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{++\exposid{current_}}. -\end{itemdescr} +\expects +\tcode{x.\exposid{it_}.valueless_by_exception()} and +\tcode{y.\exposid{it_}.valueless_by_exception()} are each \tcode{false}. -\indexlibrarymember{operator++}{elements_view::\exposid{iterator}}% -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; -\end{itemdecl} +\pnum +Let \tcode{$op$} be the operator. -\begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} -auto temp = *this; -++@\exposid{current_}@; -return temp; +return x.@\exposid{it_}@ @$op$@ y.@\exposid{it_}@; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator--}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator+}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& it, difference_type n) + requires @\exposconcept{concat-is-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -9186,14 +9435,16 @@ \effects Equivalent to: \begin{codeblock} ---@\exposid{current_}@; -return *this; +auto temp = it; +temp += n; +return temp; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator--}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator+}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& it) + requires @\exposconcept{concat-is-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -9201,16 +9452,14 @@ \effects Equivalent to: \begin{codeblock} -auto temp = *this; ---@\exposid{current_}@; -return temp; +return it + n; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+=}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& it, difference_type n) + requires @\exposconcept{concat-is-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -9218,343 +9467,475 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{current_}@ += n; -return *this; +auto temp = it; +temp -= n; +return temp; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator-=}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{concat_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{concat-is-random-access}@; \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{x.\exposid{it_}.valueless_by_exception()} and +\tcode{y.\exposid{it_}.valueless_by_exception()} are each \tcode{false}. + \pnum \effects -Equivalent to: +Let +\tcode{$i_\tcode{x}$} denote \tcode{x.\exposid{it_}.index()} and +\tcode{$i_\tcode{y}$} denote \tcode{y.\exposid{it_}.index()}. + +\begin{itemize} +\item +%FIXME This is hard to parse. +If \tcode{$i_\tcode{x}$ > $i_\tcode{y}$}, let +\tcode{$d_\tcode{y}$} be +\tcode{ranges::distance(std::get<$i_\tcode{y}$>(y.\exposid{it_}), ranges::end(std::get<$i_\tcode{y}$>(y.\linebreak{}\exposid{parent_}->\exposid{views_})))}, +\tcode{$d_\tcode{x}$} be +\tcode{ranges::distance(ranges::begin(std::get<$i_\tcode{x}$>(x.\exposid{parent_}->\linebreak{}\exposid{views_})), std::get<$i_\tcode{x}$>(x.\exposid{it_}))}. +Let \tcode{$s$} denote the sum of the sizes of all the ranges +\tcode{std::get<\linebreak{}$i$>(x.\exposid{parent_}->\exposid{views_})} +for every integer \tcode{$i$} in the range +\range{$i_\tcode{y}$ + 1}{$i_\tcode{x}$} +if there is any, and +\tcode{0} otherwise, +of type \tcode{difference_type}, +equivalent to: +\begin{codeblock} +return @$d_\tcode{y}$@ + @$s$@ + @$d_\tcode{x}$@; +\end{codeblock} + +\item +otherwise, if \tcode{$i_\tcode{x}$ < $i_\tcode{y}$} is \tcode{true}, +equivalent to: \begin{codeblock} -@\exposid{current_}@ -= n; -return *this; +return -(y - x); +\end{codeblock} + +\item +otherwise, equivalent to: +\begin{codeblock} +return std::get<@$i_\tcode{x}$@>(x.@\exposid{it_}@) - std::get<@$i_\tcode{y}$@>(y.@\exposid{it_}@); \end{codeblock} +\end{itemize} \end{itemdescr} -\indexlibrarymember{operator==}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{concat_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@<@\exposid{Base}@>; +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t) + requires @\seebelow@; \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{x.\exposid{it_}.valueless_by_exception()} is \tcode{false}. + \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} +%FIXME This is hard to parse. +Let +\tcode{$i_\tcode{x}$} denote \tcode{x.\exposid{it_}.index()}, +\tcode{$d_\tcode{x}$} be +\tcode{ranges::distance(std::get<$i_\tcode{x}$>(x.\exposid{it_}), ranges::\linebreak{}end(std::get<$i_\tcode{x}$>(x.\exposid{parent_}->\exposid{views_})))}. +Let \tcode{$s$} denote the sum of the sizes of all the ranges +\tcode{std::get<$i$>(x.\exposid{parent_}->\exposid{views_})} +for every integer \tcode{$i$} in the range +\range{$i_\tcode{x}$ + 1}{sizeof...(Views)} +if there is any, and +\tcode{0} otherwise, +of type difference_type, +equivalent to: +\begin{codeblock} +return -(@$d_\tcode{x}$@ + @$s$@); +\end{codeblock} + +\pnum +\remarks +Let \tcode{Fs} be the pack that consists of all elements of \tcode{Views} +except the first element, +%FIXME Do we want \grammarterm{expression} here? Same elsewhere? +the expression in the \grammarterm{requires-clause} is equivalent to: +\begin{codeblock} +(@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) && +(@\libconcept{sized_range}@<@\exposid{maybe-const}@> && ...) +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator<}{elements_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{concat_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr difference_type operator-(default_sentinel_t, const @\exposid{iterator}@& x) + requires @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} < y.\exposid{current_};} +Equivalent to: +\begin{codeblock} +return -(x - default_sentinel); +\end{codeblock} + +\pnum +\remarks +Let \tcode{Fs} be the pack that consists of all elements of \tcode{Views} +except the first element, +the expression in the \grammarterm{requires-clause} is equivalent to: +\begin{codeblock} +(@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) && +(@\libconcept{sized_range}@<@\exposid{maybe-const}@> && ...) +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator>}{elements_view::\exposid{iterator}}% +\indexlibrarymember{iter_move}{concat_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& it) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{it.\exposid{it_}.valueless_by_exception()} is \tcode{false}. + \pnum \effects -Equivalent to: \tcode{return y < x;} +Equivalent to: +\begin{codeblock} +return std::visit([](const auto& i) + -> @\exposid{concat-rvalue-reference-t}@<@\exposid{maybe-const}@...> { + return ranges::iter_move(i); + }, + it.@\exposid{it_}@); +\end{codeblock} + +\pnum +\remarks +The exception specification is equivalent to: +\begin{codeblock} +((is_nothrow_invocable_v>&> && + is_nothrow_convertible_v>, + @\exposid{concat-rvalue-reference-t}@<@\exposid{maybe-const}@...>>) && + ...) +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator<=}{elements_view::\exposid{iterator}}% +\indexlibrarymember{iter_swap}{concat_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept(@\seebelow@) + requires @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return !(y < x);} -\end{itemdescr} +\expects +\tcode{x.\exposid{it_}.valueless_by_exception()} and +\tcode{y.\exposid{it_}.valueless_by_exception()} are each \tcode{false}. -\indexlibrarymember{operator>=}{elements_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} - -\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(x < y);} -\end{itemdescr} - -\indexlibrarymember{operator<=>}{elements_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; -\end{itemdecl} +Equivalent to: +\begin{codeblock} +std::visit([&](const auto& it1, const auto& it2) { + if constexpr (is_same_v) { + ranges::iter_swap(it1, it2); + } else { + ranges::swap(*x, *y); + } + }, + x.@\exposid{it_}@, y.@\exposid{it_}@); +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};} +\remarks +The exception specification is equivalent to +\begin{codeblock} +(noexcept(ranges::swap(*x, *y)) && ... && noexcept(ranges::iter_swap(its, its))) +\end{codeblock} +where \tcode{its} is a pack of lvalues of type +%FIXME "respectively" doesn't make sense here. +\tcode{const iterator_t<\exposid{maybe-const}>} respectively. + +\par % This paragraph is part of the \remarks clause. +The expression in the \grammarterm{requires-clause} is equivalent to +\begin{codeblock} +@\libconcept{swappable_with}@, iter_reference_t<@\exposid{iterator}@>> && +(... && @\libconcept{indirectly_swappable}@>>) +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+}{elements_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} +\rSec2[range.counted]{Counted view} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return \exposid{iterator}\{x\} += y;} -\end{itemdescr} +\indextext{range!counted}% +A counted view presents a view of the elements +of the counted range\iref{iterator.requirements.general} \countedrange{i}{n} +for an iterator \tcode{i} and non-negative integer \tcode{n}. -\indexlibrarymember{operator+}{elements_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} +\pnum +\indexlibrarymember{counted}{views}% +The name \tcode{views::counted} denotes +a customization point object\iref{customization.point.object}. +Let \tcode{E} and \tcode{F} be expressions, +let \tcode{T} be \tcode{decay_t}, and +let \tcode{D} be \tcode{iter_difference_t}. +If \tcode{decltype((F))} does not model +\tcode{\libconcept{convertible_to}}, +\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} +Otherwise, \tcode{views::counted(E, F)} +is expression-equivalent to: + +\begin{itemize} +\item +If \tcode{T} models \libconcept{contiguous_iterator}, +then \tcode{span(to_address(E), static_cast(static_-\linebreak{}cast(F)))}. + +\item +Otherwise, if \tcode{T} models \libconcept{random_access_iterator}, +then \tcode{subrange(E, E + static_cast(F))}, +except that \tcode{E} is evaluated only once. + +\item +Otherwise, +\tcode{subrange(counted_iterator(E, F), default_sentinel)}. +\end{itemize} + +\rSec2[range.common]{Common view} + +\rSec3[range.common.overview]{Overview} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return y + x;} -\end{itemdescr} +\tcode{common_view} takes a view which has different types for +its iterator and sentinel and turns it into a view of the same +elements with an iterator and sentinel of the same type. -\indexlibrarymember{operator-}{elements_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} +\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} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return \exposid{iterator}\{x\} -= y;} -\end{itemdescr} +\indexlibrarymember{common}{views}% +The name \tcode{views::common} denotes a +range adaptor object\iref{range.adaptor.object}. +Given a 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. -\indexlibrarymember{operator-}{elements_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; -\end{itemdecl} +\item Otherwise, \tcode{common_view\{E\}}. +\end{itemize} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{current_};} -\end{itemdescr} +\begin{example} +\begin{codeblock} +// Legacy algorithm: +template +size_t count(ForwardIterator first, ForwardIterator last); -\rSec3[range.elements.sentinel]{Class template \tcode{elements_view::\exposid{sentinel}}} +template<@\libconcept{forward_range}@ R> +void my_algo(R&& r) { + auto&& common = views::common(r); + auto cnt = count(common.begin(), common.end()); + // ... +} +\end{codeblock} +\end{example} + +\rSec3[range.common.view]{Class template \tcode{common_view}} +\indexlibraryglobal{common_view}% +\indexlibrarymember{base}{common_view}% +\indexlibrarymember{size}{common_view}% +\indexlibrarymember{begin}{common_view}% +\indexlibrarymember{end}{common_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ V, size_t N> - requires @\libconcept{view}@ && @\exposconcept{has-tuple-element}@, N> && - @\exposconcept{has-tuple-element}@>, N> && - @\exposconcept{returnable-element}@, N> - template - class elements_view::@\exposid{sentinel}@ { + template<@\libconcept{view}@ V> + requires (!@\libconcept{common_range}@ && @\libconcept{copyable}@>) + class common_view : public view_interface> { private: - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos - sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + V @\exposid{base_}@ = V(); // \expos public: - @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + common_view() requires @\libconcept{default_initializable}@ = default; - constexpr sentinel_t<@\exposid{Base}@> base() const; + constexpr explicit common_view(V r); - template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } - template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + constexpr auto begin() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) + return ranges::begin(@\exposid{base_}@); + else + return common_iterator, sentinel_t>(ranges::begin(@\exposid{base_}@)); + } - template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + constexpr auto begin() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) + return ranges::begin(@\exposid{base_}@); + else + return common_iterator, sentinel_t>(ranges::begin(@\exposid{base_}@)); + } + + constexpr auto end() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) + return ranges::begin(@\exposid{base_}@) + ranges::distance(@\exposid{base_}@); + else + return common_iterator, sentinel_t>(ranges::end(@\exposid{base_}@)); + } + + constexpr auto end() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) + return ranges::begin(@\exposid{base_}@) + ranges::distance(@\exposid{base_}@); + else + return common_iterator, sentinel_t>(ranges::end(@\exposid{base_}@)); + } + + constexpr auto size() requires @\libconcept{sized_range}@ { + return ranges::size(@\exposid{base_}@); + } + constexpr auto size() const requires @\libconcept{sized_range}@ { + return ranges::size(@\exposid{base_}@); + } + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ { + return ranges::reserve_hint(@\exposid{base_}@); + } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ { + return ranges::reserve_hint(@\exposid{base_}@); + } }; + + template + common_view(R&&) -> common_view>; } \end{codeblock} -\indexlibraryctor{elements_view::\exposid{sentinel}}% +\indexlibraryctor{common_view}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); +constexpr explicit common_view(V base); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end}. +Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\indexlibraryctor{elements_view::\exposid{sentinel}}% -\begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{end_} with \tcode{std::move(other.\exposid{end_})}. -\end{itemdescr} +\rSec2[range.reverse]{Reverse view} -\indexlibrarymember{base}{elements_view::\exposid{sentinel}}% -\begin{itemdecl} -constexpr sentinel_t<@\exposid{Base}@> base() const; -\end{itemdecl} +\rSec3[range.reverse.overview]{Overview} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return \exposid{end_};} -\end{itemdescr} - -\indexlibrarymember{operator==}{elements_view::\exposid{sentinel}}% -\begin{itemdecl} -template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); -\end{itemdecl} +\tcode{reverse_view} takes a bidirectional view and produces +another view that iterates the same elements in reverse order. -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} -\end{itemdescr} - -\indexlibrarymember{operator-}{elements_view::\exposid{sentinel}}% -\begin{itemdecl} -template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{end_};} -\end{itemdescr} - -\indexlibrarymember{operator-}{elements_view::\exposid{sentinel}}% -\begin{itemdecl} -template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return x.\exposid{end_} - y.\exposid{current_};} -\end{itemdescr} - -\rSec2[range.enumerate]{Enumerate view} - -\rSec3[range.enumerate.overview]{Overview} - -\pnum -\indexlibraryglobal{enumerate_view}% -\tcode{enumerate_view} is a view whose -elements represent both the position and value from -a sequence of elements. +\indexlibrarymember{reverse}{views}% +The name \tcode{views::reverse} denotes a +range adaptor object\iref{range.adaptor.object}. +Given a 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}, + then \tcode{E.base()}. +\item + Otherwise, if the type of \tcode{E} is \cv{} \tcode{subrange, reverse_iterator, K>} + 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}, then +\tcode{subrange(E.end().base(), E.begin().base(), E.size())}; + \item + otherwise, \tcode{subrange(E.end().base(), E.begin().base())}. + \end{itemize} + However, in either case \tcode{E} is evaluated only once. +\item + Otherwise, \tcode{reverse_view\{E\}}. +\end{itemize} \pnum -\indexlibrarymember{enumerate}{views}% -The name \tcode{views::enumerate} denotes a range adaptor object\iref{range.adaptor.object}. -Given a subexpression \tcode{E}, -the expression \tcode{views::enumerate(E)} is expression-equivalent to -\tcode{enumerate_view>(E)}. \begin{example} \begin{codeblock} -vector vec{ 1, 2, 3 }; -for (auto [index, value] : views::enumerate(vec)) - cout << index << ":" << value << ' '; // prints \tcode{0:1 1:2 2:3} +vector is {0,1,2,3,4}; +for (int i : is | views::reverse) + cout << i << ' '; // prints \tcode{4 3 2 1 0} \end{codeblock} \end{example} -\rSec3[range.enumerate.view]{Class template \tcode{enumerate_view}} +\rSec3[range.reverse.view]{Class template \tcode{reverse_view}} -\indexlibrarymember{begin}{enumerate_view}% -\indexlibrarymember{end}{enumerate_view}% -\indexlibrarymember{size}{enumerate_view}% +\indexlibraryglobal{reverse_view}% +\indexlibrarymember{base}{reverse_view}% +\indexlibrarymember{size}{reverse_view}% \begin{codeblock} namespace std::ranges { template<@\libconcept{view}@ V> - requires @\exposconcept{range-with-movable-references}@ - class enumerate_view : public view_interface> { - V @\exposidnc{base_}@ = V(); // \expos + requires @\libconcept{bidirectional_range}@ + class reverse_view : public view_interface> { + private: + V @\exposid{base_}@ = V(); // \expos - // \ref{range.enumerate.iterator}, class template \tcode{enumerate_view::\exposid{iterator}} - template - class @\exposidnc{iterator}@; // \expos + public: + reverse_view() requires @\libconcept{default_initializable}@ = default; - // \ref{range.enumerate.sentinel}, class template \tcode{enumerate_view::\exposid{sentinel}} - template - class @\exposidnc{sentinel}@; // \expos + constexpr explicit reverse_view(V r); - public: - constexpr enumerate_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit enumerate_view(V base); + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } - constexpr auto begin() requires (!@\exposconcept{simple-view}@) - { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), 0); } - constexpr auto begin() const requires @\exposconcept{range-with-movable-references}@ - { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), 0); } + constexpr reverse_iterator> begin(); + constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; + constexpr auto begin() const requires @\libconcept{common_range}@; - constexpr auto end() requires (!@\exposconcept{simple-view}@) { - if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@) - return @\exposid{iterator}@(ranges::end(@\exposid{base_}@), ranges::distance(@\exposid{base_}@)); - else - return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); - } - constexpr auto end() const requires @\exposconcept{range-with-movable-references}@ { - if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@) - return @\exposid{iterator}@(ranges::end(@\exposid{base_}@), ranges::distance(@\exposid{base_}@)); - else - return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); + constexpr reverse_iterator> end(); + constexpr auto end() const requires @\libconcept{common_range}@; + + constexpr auto size() requires @\libconcept{sized_range}@ { + return ranges::size(@\exposid{base_}@); } - constexpr auto size() requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{base_}@); } - constexpr auto size() const requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{base_}@); } + constexpr auto size() const requires @\libconcept{sized_range}@ { + return ranges::size(@\exposid{base_}@); + } - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ { + return ranges::reserve_hint(@\exposid{base_}@); + } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ { + return ranges::reserve_hint(@\exposid{base_}@); + } }; template - enumerate_view(R&&) -> enumerate_view>; + reverse_view(R&&) -> reverse_view>; } \end{codeblock} +\indexlibraryctor{reverse_view}% \begin{itemdecl} -constexpr explicit enumerate_view(V base); +constexpr explicit reverse_view(V base); \end{itemdecl} \begin{itemdescr} @@ -9563,160 +9944,1629 @@ Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\rSec3[range.enumerate.iterator]{Class template \tcode{enumerate_view::\exposid{iterator}}} +\indexlibrarymember{begin}{reverse_view}% +\begin{itemdecl} +constexpr reverse_iterator> begin(); +\end{itemdecl} -\indexlibraryglobal{enumerate_view::\exposid{iterator}}% +\begin{itemdescr} +\pnum +\returns \begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\exposconcept{range-with-movable-references}@ - template - class enumerate_view::@\exposid{iterator}@ { - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - - public: - using iterator_category = input_iterator_tag; - using iterator_concept = @\seebelow@; - using difference_type = range_difference_t<@\exposid{Base}@>; - using value_type = tuple>; - - private: - using @\exposidnc{reference-type}@ = // \expos - tuple>; - iterator_t<@\exposidnc{Base}@> @\exposidnc{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos - difference_type @\exposidnc{pos_}@ = 0; // \expos - - constexpr explicit - @\exposidnc{iterator}@(iterator_t<@\exposidnc{Base}@> current, difference_type pos); // \expos - - public: - @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; - - constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; - constexpr iterator_t<@\exposid{Base}@> base() &&; - - constexpr difference_type index() const noexcept; - - constexpr auto operator*() const { - return @\exposid{reference-type}@(@\exposid{pos_}@, *@\exposid{current_}@); - } - - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; - - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - - constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - - constexpr auto operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@> - { return @\exposid{reference-type}@(@\exposid{pos_}@ + n, @\exposid{current_}@[n]); } - - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; - friend constexpr strong_ordering operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; - - friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; - - friend constexpr auto iter_move(const @\exposid{iterator}@& i) - noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)) && - is_nothrow_move_constructible_v>) { - return tuple>(i.@\exposid{pos_}@, ranges::iter_move(i.@\exposid{current_}@)); - } - }; -} +make_reverse_iterator(ranges::next(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@))) \end{codeblock} \pnum -The member \grammarterm{typedef-name} -\tcode{\exposid{iterator}::iterator_concept} -is defined as follows: -\begin{itemize} -\item -If \exposid{Base} models \libconcept{random_access_range}, -then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. -\item -Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item -Otherwise, if \exposid{Base} models \libconcept{forward_range}, -then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. -\item -Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. -\end{itemize} +\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} -\indexlibraryctor{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{begin}{reverse_view}% \begin{itemdecl} -constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, difference_type pos); +constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; +constexpr auto begin() const requires @\libconcept{common_range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(current)} and -\exposid{pos_} with \tcode{pos}. +Equivalent to: \tcode{return make_reverse_iterator(ranges::end(\exposid{base_}));} \end{itemdescr} -\indexlibraryctor{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{end}{reverse_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +constexpr reverse_iterator> end(); +constexpr auto end() const requires @\libconcept{common_range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})} and -\exposid{pos_} with \tcode{i.\exposid{pos_}}. +Equivalent to: \tcode{return make_reverse_iterator(ranges::begin(\exposid{base_}));} \end{itemdescr} -\indexlibrarymember{base}{enumerate_view::\exposid{iterator}}% -\begin{itemdecl} +\rSec2[range.as.const]{As const view} + +\rSec3[range.as.const.overview]{Overview} + +\pnum +\tcode{as_const_view} presents a view of an underlying sequence as constant. +That is, the elements of an \tcode{as_const_view} cannot be modified. + +\pnum +The name \tcode{views::as_const} denotes +a range adaptor object\iref{range.adaptor.object}. +Let \tcode{E} be an expression, +let \tcode{T} be \tcode{decltype((E))}, and +let \tcode{U} be \tcode{remove_cvref_t}. +The expression \tcode{views::as_const(E)} is expression-equivalent to: +\begin{itemize} +\item +If \tcode{views::all_t} models \libconcept{constant_range}, +then \tcode{views::all(E)}. +\item +Otherwise, +if \tcode{U} denotes \tcode{empty_view} +for some type \tcode{X}, then \tcode{auto(views::empty)}. +\item +Otherwise, +if \tcode{U} denotes \tcode{span} +for some type \tcode{X} and some extent \tcode{Extent}, +then \tcode{span(E)}. +\item +Otherwise, +if \tcode{U} denotes \tcode{ref_view} for some type \tcode{X} and +\tcode{const X} models \libconcept{constant_range}, +then \tcode{ref_view(static_cast(E.base()))}. +\item +Otherwise, +if \tcode{E} is an lvalue, +\tcode{const U} models \libconcept{constant_range}, and +\tcode{U} does not model \libconcept{view}, +then \tcode{ref_view(static_cast(E))}. +\item +Otherwise, \tcode{as_const_view(E)}. +\end{itemize} + +\pnum +\begin{example} +\begin{codeblock} +template<@\libconcept{constant_range}@ R> +void cant_touch_this(R&&); + +vector hammer = {'m', 'c'}; +span beat = hammer; +cant_touch_this(views::as_const(beat)); // will not modify the elements of \tcode{hammer} +\end{codeblock} +\end{example} + +\rSec3[range.as.const.view]{Class template \tcode{as_const_view}} + +\indexlibraryglobal{as_const_view::\exposid{iterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + class as_const_view : public view_interface> { + V @\exposid{base_}@ = V(); // \expos + + public: + as_const_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit as_const_view(V base); + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + + constexpr auto begin() requires (!@\exposconcept{simple-view}@) { return ranges::cbegin(@\exposid{base_}@); } + constexpr auto begin() const requires @\libconcept{range}@ { return ranges::cbegin(@\exposid{base_}@); } + + constexpr auto end() requires (!@\exposconcept{simple-view}@) { return ranges::cend(@\exposid{base_}@); } + constexpr auto end() const requires @\libconcept{range}@ { return ranges::cend(@\exposid{base_}@); } + + constexpr auto size() requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } + constexpr auto size() const requires @\libconcept{sized_range}@ { return ranges::size(@\exposid{base_}@); } + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + }; + + template + as_const_view(R&&) -> as_const_view>; +} +\end{codeblock} + +\indexlibraryctor{as_const_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr explicit as_const_view(V base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\rSec2[range.elements]{Elements view} + +\rSec3[range.elements.overview]{Overview} + +\pnum +\tcode{elements_view} takes +a view of tuple-like values and a \tcode{size_t}, and +produces a view with a value-type of the $N^\text{th}$ element +of the adapted view's value-type. + +\pnum +\indexlibrarymember{elements}{views}% +The name \tcode{views::elements} denotes +a range adaptor object\iref{range.adaptor.object}. +Given a subexpression \tcode{E} and constant expression \tcode{N}, +the expression \tcode{views::elements(E)} is expression-equivalent to +\tcode{elements_view, N>\{E\}}. + +\begin{example} +\begin{codeblock} +auto historical_figures = map{ + pair{"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 +\tcode{keys_view} is an alias for \tcode{elements_view}, and +is useful for extracting keys from associative containers. + +\begin{example} +\begin{codeblock} +auto names = historical_figures | views::keys; +for (auto&& name : names) { + cout << name << ' '; // prints \tcode{Babbage Hamilton Lovelace Turing } +} +\end{codeblock} +\end{example} + +\pnum +\tcode{values_view} is an alias for \tcode{elements_view}, and +is useful for extracting values from associative containers. + +\begin{example} +\begin{codeblock} +auto is_even = [](const auto x) { return x % 2 == 0; }; +cout << ranges::count_if(historical_figures | views::values, is_even); // prints \tcode{2} +\end{codeblock} +\end{example} + +\rSec3[range.elements.view]{Class template \tcode{elements_view}} + +\indexlibraryglobal{elements_view}% +\indexlibrarymember{base}{elements_view}% +\indexlibrarymember{begin}{elements_view}% +\indexlibrarymember{end}{elements_view}% +\indexlibrarymember{size}{elements_view}% +\begin{codeblock} +namespace std::ranges { + template + concept @\defexposconcept{has-tuple-element}@ = // \expos + @\exposconcept{tuple-like}@ && N < tuple_size_v; + + template + concept @\defexposconcept{returnable-element}@ = // \expos + is_reference_v || @\libconcept{move_constructible}@>; + + template<@\libconcept{input_range}@ V, size_t N> + requires @\libconcept{view}@ && @\exposconcept{has-tuple-element}@, N> && + @\exposconcept{has-tuple-element}@>, N> && + @\exposconcept{returnable-element}@, N> + class elements_view : public view_interface> { + public: + elements_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit elements_view(V base); + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + + constexpr auto begin() requires (!@\exposconcept{simple-view}@) + { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@)); } + + constexpr auto begin() const requires @\libconcept{range}@ + { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@)); } + + constexpr auto end() requires (!@\exposconcept{simple-view}@ && !@\libconcept{common_range}@) + { return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; } + + constexpr auto end() requires (!@\exposconcept{simple-view}@ && @\libconcept{common_range}@) + { return @\exposid{iterator}@{ranges::end(@\exposid{base_}@)}; } + + constexpr auto end() const requires @\libconcept{range}@ + { return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; } + + constexpr auto end() const requires @\libconcept{common_range}@ + { return @\exposid{iterator}@{ranges::end(@\exposid{base_}@)}; } + + constexpr auto size() requires @\libconcept{sized_range}@ + { return ranges::size(@\exposid{base_}@); } + + constexpr auto size() const requires @\libconcept{sized_range}@ + { return ranges::size(@\exposid{base_}@); } + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + + private: + // \ref{range.elements.iterator}, class template \tcode{elements_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos + + // \ref{range.elements.sentinel}, class template \tcode{elements_view::\exposid{sentinel}} + template class @\exposid{sentinel}@; // \expos + + V @\exposid{base_}@ = V(); // \expos + }; +} +\end{codeblock} + +\indexlibraryctor{elements_view}% +\begin{itemdecl} +constexpr explicit elements_view(V base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\rSec3[range.elements.iterator]{Class template \tcode{elements_view::\exposid{iterator}}} + +\indexlibraryglobal{elements_view::\exposid{iterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, size_t N> + requires @\libconcept{view}@ && @\exposconcept{has-tuple-element}@, N> && + @\exposconcept{has-tuple-element}@>, N> && + @\exposconcept{returnable-element}@, N> + template + class elements_view::@\exposid{iterator}@ { + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + + iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos + + static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); // \expos + + public: + using iterator_concept = @\seebelow@; + using iterator_category = @\seebelow@; // not always present + using value_type = remove_cvref_t>>; + using difference_type = range_difference_t<@\exposid{Base}@>; + + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; + constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; + + constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; + constexpr iterator_t<@\exposid{Base}@> base() &&; + + constexpr decltype(auto) operator*() const + { return @\exposid{get-element}@(@\exposid{current_}@); } + + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; + + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + + constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + constexpr decltype(auto) operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@> + { return @\exposid{get-element}@(@\exposid{current_}@ + n); } + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{equality_comparable}@>; + + friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; + + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + }; +} +\end{codeblock} + +\pnum +The member \grammarterm{typedef-name} \tcode{iterator_concept} +is defined as follows: +\begin{itemize} +\item +If \exposid{Base} models \libconcept{random_access_range}, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, if \exposid{Base} models \libconcept{forward_range}, +then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\pnum +The member \grammarterm{typedef-name} \tcode{iterator_category} is defined +if and only if \exposid{Base} models \libconcept{forward_range}. +In that case, \tcode{iterator_category} is defined as follows: +Let \tcode{C} denote the type +\tcode{iterator_traits>::iterator_category}. +\begin{itemize} +\item +If \tcode{std::get(*\exposid{current_})} is an rvalue, +\tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\item +Otherwise, if \tcode{C} models \tcode{\libconcept{derived_from}}, +\tcode{iterator_category} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, \tcode{iterator_category} denotes \tcode{C}. +\end{itemize} + +\begin{itemdecl} +static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if constexpr (is_reference_v>) { + return std::get(*i); +} else { + using E = remove_cv_t>>; + return static_cast(std::get(*i)); +} +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(current)}. +\end{itemdescr} + +\indexlibraryctor{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +\end{itemdescr} + +\indexlibrarymember{base}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{base}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr iterator_t<@\exposid{Base}@> base() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return std::move(\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{operator++}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +++@\exposid{current_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{++\exposid{current_}}. +\end{itemdescr} + +\indexlibrarymember{operator++}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto temp = *this; +++@\exposid{current_}@; +return temp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +--@\exposid{current_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto temp = *this; +--@\exposid{current_}@; +return temp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+=}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator+=(difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ += n; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator-=}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator-=(difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ -= n; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator==}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{equality_comparable}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator<}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} < y.\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator>}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return y < x;} +\end{itemdescr} + +\indexlibrarymember{operator<=}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return !(y < x);} +\end{itemdescr} + +\indexlibrarymember{operator>=}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return !(x < y);} +\end{itemdescr} + +\indexlibrarymember{operator<=>}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator+}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}\{x\} += y;} +\end{itemdescr} + +\indexlibrarymember{operator+}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return y + x;} +\end{itemdescr} + +\indexlibrarymember{operator-}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}\{x\} -= y;} +\end{itemdescr} + +\indexlibrarymember{operator-}{elements_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{current_};} +\end{itemdescr} + +\rSec3[range.elements.sentinel]{Class template \tcode{elements_view::\exposid{sentinel}}} + +\indexlibraryglobal{elements_view::\exposid{sentinel}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, size_t N> + requires @\libconcept{view}@ && @\exposconcept{has-tuple-element}@, N> && + @\exposconcept{has-tuple-element}@>, N> && + @\exposconcept{returnable-element}@, N> + template + class elements_view::@\exposid{sentinel}@ { + private: + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + + public: + @\exposid{sentinel}@() = default; + constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + + constexpr sentinel_t<@\exposid{Base}@> base() const; + + template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + + template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + + template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + }; +} +\end{codeblock} + +\indexlibraryctor{elements_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{end}. +\end{itemdescr} + +\indexlibraryctor{elements_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(other.\exposid{end_})}. +\end{itemdescr} + +\indexlibrarymember{base}{elements_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr sentinel_t<@\exposid{Base}@> base() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{end_};} +\end{itemdescr} + +\indexlibrarymember{operator==}{elements_view::\exposid{sentinel}}% +\begin{itemdecl} +template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} +\end{itemdescr} + +\indexlibrarymember{operator-}{elements_view::\exposid{sentinel}}% +\begin{itemdecl} +template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{end_};} +\end{itemdescr} + +\indexlibrarymember{operator-}{elements_view::\exposid{sentinel}}% +\begin{itemdecl} +template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{end_} - y.\exposid{current_};} +\end{itemdescr} + +\rSec2[range.enumerate]{Enumerate view} + +\rSec3[range.enumerate.overview]{Overview} + +\pnum +\indexlibraryglobal{enumerate_view}% +\tcode{enumerate_view} is a view whose +elements represent both the position and value from +a sequence of elements. + +\pnum +\indexlibrarymember{enumerate}{views}% +The name \tcode{views::enumerate} denotes a range adaptor object\iref{range.adaptor.object}. +Given a subexpression \tcode{E}, +the expression \tcode{views::enumerate(E)} is expression-equivalent to +\tcode{enumerate_view>(E)}. +\begin{example} +\begin{codeblock} +vector vec{ 1, 2, 3 }; +for (auto [index, value] : views::enumerate(vec)) + cout << index << ":" << value << ' '; // prints \tcode{0:1 1:2 2:3} +\end{codeblock} +\end{example} + +\rSec3[range.enumerate.view]{Class template \tcode{enumerate_view}} + +\indexlibraryglobal{enumerate_view}% +\indexlibrarymember{begin}{enumerate_view}% +\indexlibrarymember{end}{enumerate_view}% +\indexlibrarymember{size}{enumerate_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\exposconcept{range-with-movable-references}@ + class enumerate_view : public view_interface> { + V @\exposidnc{base_}@ = V(); // \expos + + // \ref{range.enumerate.iterator}, class template \tcode{enumerate_view::\exposid{iterator}} + template + class @\exposidnc{iterator}@; // \expos + + // \ref{range.enumerate.sentinel}, class template \tcode{enumerate_view::\exposid{sentinel}} + template + class @\exposidnc{sentinel}@; // \expos + + public: + constexpr enumerate_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit enumerate_view(V base); + + constexpr auto begin() requires (!@\exposconcept{simple-view}@) + { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), 0); } + constexpr auto begin() const requires @\exposconcept{range-with-movable-references}@ + { return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), 0); } + + constexpr auto end() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{forward_range}@ && @\libconcept{common_range}@ && @\libconcept{sized_range}@) + return @\exposid{iterator}@(ranges::end(@\exposid{base_}@), ranges::distance(@\exposid{base_}@)); + else + return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); + } + constexpr auto end() const requires @\exposconcept{range-with-movable-references}@ { + if constexpr (@\libconcept{forward_range}@ && @\libconcept{common_range}@ && @\libconcept{sized_range}@) + return @\exposid{iterator}@(ranges::end(@\exposid{base_}@), ranges::distance(@\exposid{base_}@)); + else + return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); + } + + constexpr auto size() requires @\libconcept{sized_range}@ + { return ranges::size(@\exposid{base_}@); } + constexpr auto size() const requires @\libconcept{sized_range}@ + { return ranges::size(@\exposid{base_}@); } + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ + { return ranges::reserve_hint(@\exposid{base_}@); } + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + }; + + template + enumerate_view(R&&) -> enumerate_view>; +} +\end{codeblock} + +\indexlibraryctor{enumerate_view}% +\begin{itemdecl} +constexpr explicit enumerate_view(V base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\rSec3[range.enumerate.iterator]{Class template \tcode{enumerate_view::\exposid{iterator}}} + +\indexlibraryglobal{enumerate_view::\exposid{iterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\exposconcept{range-with-movable-references}@ + template + class enumerate_view::@\exposid{iterator}@ { + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + + public: + using iterator_category = input_iterator_tag; + using iterator_concept = @\seebelow@; + using difference_type = range_difference_t<@\exposid{Base}@>; + using value_type = tuple>; + + private: + using @\exposidnc{reference-type}@ = // \expos + tuple>; + iterator_t<@\exposidnc{Base}@> @\exposidnc{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos + difference_type @\exposidnc{pos_}@ = 0; // \expos + + constexpr explicit + @\exposidnc{iterator}@(iterator_t<@\exposidnc{Base}@> current, difference_type pos); // \expos + + public: + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; + + constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; + constexpr iterator_t<@\exposid{Base}@> base() &&; + + constexpr difference_type index() const noexcept; + + constexpr auto operator*() const { + return @\exposid{reference-type}@(@\exposid{pos_}@, *@\exposid{current_}@); + } + + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; + + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + + constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + constexpr auto operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@> + { return @\exposid{reference-type}@(@\exposid{pos_}@ + n, @\exposid{current_}@[n]); } + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; + friend constexpr strong_ordering operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; + + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; + + friend constexpr auto iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@)) && + is_nothrow_move_constructible_v>) { + return tuple>(i.@\exposid{pos_}@, ranges::iter_move(i.@\exposid{current_}@)); + } + }; +} +\end{codeblock} + +\pnum +The member \grammarterm{typedef-name} +\tcode{\exposid{iterator}::iterator_concept} +is defined as follows: +\begin{itemize} +\item +If \exposid{Base} models \libconcept{random_access_range}, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, if \exposid{Base} models \libconcept{forward_range}, +then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\indexlibraryctor{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, difference_type pos); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(current)} and +\exposid{pos_} with \tcode{pos}. +\end{itemdescr} + +\indexlibraryctor{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})} and +\exposid{pos_} with \tcode{i.\exposid{pos_}}. +\end{itemdescr} + +\indexlibrarymember{base}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{current_};} +Equivalent to: \tcode{return \exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{base}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr iterator_t<@\exposid{Base}@> base() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return std::move(\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{index}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr difference_type index() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{pos_};} +\end{itemdescr} + +\indexlibrarymember{operator++}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +++@\exposid{current_}@; +++@\exposid{pos_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{++*this}. +\end{itemdescr} + +\indexlibrarymember{operator++}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto temp = *this; +++*this; +return temp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +--@\exposid{current_}@; +--@\exposid{pos_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto temp = *this; +--*this; +return temp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+=}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator+=(difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ += n; +@\exposid{pos_}@ += n; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator-=}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator-=(difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ -= n; +@\exposid{pos_}@ -= n; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator==}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{pos_} == y.\exposid{pos_};} +\end{itemdescr} + +\indexlibrarymember{operator<=>}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr strong_ordering operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{pos_} <=> y.\exposid{pos_};} +\end{itemdescr} + +\indexlibrarymember{operator+}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto temp = x; +temp += y; +return temp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return y + x;} +\end{itemdescr} + +\indexlibrarymember{operator-}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto temp = x; +temp -= y; +return temp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator-}{enumerate_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{pos_} - y.\exposid{pos_};} +\end{itemdescr} + +\rSec3[range.enumerate.sentinel]{Class template \tcode{enumerate_view::\exposid{sentinel}}} + +\indexlibraryglobal{enumerate_view::\exposid{sentinel}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\exposconcept{range-with-movable-references}@ + template + class enumerate_view::@\exposid{sentinel}@ { + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + sentinel_t<@\exposidnc{Base}@> @\exposidnc{end_}@ = sentinel_t<@\exposidnc{Base}@>(); // \expos + constexpr explicit @\exposidnc{sentinel}@(sentinel_t<@\exposidnc{Base}@> end); // \expos + + public: + @\exposid{sentinel}@() = default; + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + + constexpr sentinel_t<@\exposid{Base}@> base() const; + + template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + + template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + + template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + }; +} +\end{codeblock} + +\indexlibraryctor{enumerate_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(end)}. +\end{itemdescr} + +\indexlibraryctor{enumerate_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(other.\exposid{end_})}. +\end{itemdescr} + +\indexlibrarymember{base}{enumerate_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr sentinel_t<@\exposid{Base}@> base() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{end_};} +\end{itemdescr} + +\indexlibrarymember{operator==}{enumerate_view::\exposid{sentinel}}% +\begin{itemdecl} +template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} +\end{itemdescr} + +\indexlibrarymember{operator-}{enumerate_view::\exposid{sentinel}}% +\begin{itemdecl} +template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{end_};} +\end{itemdescr} + +\indexlibrarymember{operator-}{enumerate_view::\exposid{sentinel}}% +\begin{itemdecl} +template + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{end_} - y.\exposid{current_};} +\end{itemdescr} + +\rSec2[range.zip]{Zip view} + +\rSec3[range.zip.overview]{Overview} + +\pnum +\indexlibraryglobal{zip_view}% +\tcode{zip_view} takes any number of views and +produces a view of tuples of references +to the corresponding elements of the constituent views. + +\pnum +\indexlibrarymember{zip}{views}% +The name \tcode{views::zip} denotes +a customization point object\iref{customization.point.object}. +Given a pack of subexpressions \tcode{Es...}, +the expression \tcode{views::zip(Es...)} is expression-equivalent to +\begin{itemize} +\item +\tcode{auto(views::empty>)} +if \tcode{Es} is an empty pack, +\item +otherwise, \tcode{zip_view...>(Es...)}. +\end{itemize} + +\begin{example} +\begin{codeblock} +vector v = {1, 2}; +list l = {'a', 'b', 'c'}; + +auto z = views::zip(v, l); +range_reference_t f = z.front(); // \tcode{f} is a \tcode{tuple} + // that refers to the first element of \tcode{v} and \tcode{l} + +for (auto&& [x, y] : z) { + cout << '(' << x << ", " << y << ") "; // prints \tcode{(1, a) (2, b)} +} +\end{codeblock} +\end{example} + +\rSec3[range.zip.view]{Class template \tcode{zip_view}} + +\indexlibraryglobal{zip_view}% +\indexlibrarymember{begin}{zip_view}% +\indexlibrarymember{end}{zip_view}% +\begin{codeblock} +namespace std::ranges { + template + concept @\defexposconcept{zip-is-common}@ = // \expos + (sizeof...(Rs) == 1 && (@\libconcept{common_range}@ && ...)) || + (!(@\libconcept{bidirectional_range}@ && ...) && (@\libconcept{common_range}@ && ...)) || + ((@\libconcept{random_access_range}@ && ...) && (@\libconcept{sized_range}@ && ...)); + + template<@\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) + class zip_view : public view_interface> { + tuple @\exposid{views_}@; // \expos + + // \ref{range.zip.iterator}, class template \tcode{zip_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos + + // \ref{range.zip.sentinel}, class template \tcode{zip_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos + + public: + zip_view() = default; + constexpr explicit zip_view(Views... views); + + constexpr auto begin() requires (!(@\exposconcept{simple-view}@ && ...)) { + return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::begin, @\exposid{views_}@)); + } + constexpr auto begin() const requires (@\libconcept{range}@ && ...) { + return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::begin, @\exposid{views_}@)); + } + + constexpr auto end() requires (!(@\exposconcept{simple-view}@ && ...)) { + if constexpr (!@\exposconcept{zip-is-common}@) { + return @\exposid{sentinel}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + } else if constexpr ((@\libconcept{random_access_range}@ && ...)) { + return begin() + iter_difference_t<@\exposid{iterator}@>(size()); + } else { + return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + } + } + + constexpr auto end() const requires (@\libconcept{range}@ && ...) { + if constexpr (!@\exposconcept{zip-is-common}@) { + return @\exposid{sentinel}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + } else if constexpr ((@\libconcept{random_access_range}@ && ...)) { + return begin() + iter_difference_t<@\exposid{iterator}@>(size()); + } else { + return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + } + } + + constexpr auto size() requires (@\libconcept{sized_range}@ && ...); + constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); + }; + + template + zip_view(Rs&&...) -> zip_view...>; +} +\end{codeblock} + +\pnum +Two \tcode{zip_view} objects have the same underlying sequence if and only if +the corresponding elements of \exposid{views_} are equal\iref{concepts.equality} +and have the same underlying sequence. +\begin{note} +In particular, comparison of iterators obtained from \tcode{zip_view} objects +that do not have the same underlying sequence +is not required to produce meaningful results\iref{iterator.concept.forward}. +\end{note} + +\indexlibraryctor{zip_view}% +\begin{itemdecl} +constexpr explicit zip_view(Views... views); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{views_} with \tcode{std::move(views)...}. \end{itemdescr} -\indexlibrarymember{base}{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{size}{zip_view}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() &&; +constexpr auto size() requires (@\libconcept{sized_range}@ && ...); +constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return std::move(\exposid{current_});} +Equivalent to: +\begin{codeblock} +return apply([](auto... sizes) { + using CT = @\exposid{make-unsigned-like-t}@>; + return ranges::min({CT(sizes)...}); +}, @\exposid{tuple-transform}@(ranges::size, @\exposid{views_}@)); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{index}{enumerate_view::\exposid{iterator}}% +\rSec3[range.zip.iterator]{Class template \tcode{zip_view::\exposid{iterator}}} + +\indexlibraryglobal{zip_view::\exposid{iterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) + template + class zip_view::@\exposid{iterator}@ { + tuple>...> @\exposid{current_}@;@\itcorr[-1]@ // \expos + constexpr explicit @\exposidnc{iterator}@(tuple>...>); + // \expos + public: + using iterator_category = input_iterator_tag; // not always present + using iterator_concept = @\seebelow@; + using value_type = tuple>...>; + using difference_type = common_type_t>...>; + + @\exposid{iterator}@() = default; + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && (@\libconcept{convertible_to}@, iterator_t> && ...); + + constexpr auto operator*() const; + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\exposconcept{all-forward}@; + + constexpr @\exposid{iterator}@& operator--() requires @\exposconcept{all-bidirectional}@; + constexpr @\exposid{iterator}@ operator--(int) requires @\exposconcept{all-bidirectional}@; + + constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\exposconcept{all-random-access}@; + constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\exposconcept{all-random-access}@; + + constexpr auto operator[](difference_type n) const + requires @\exposconcept{all-random-access}@; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{equality_comparable}@>> && ...); + + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; + + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) + requires @\exposconcept{all-random-access}@; + friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) + requires @\exposconcept{all-random-access}@; + friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\exposconcept{all-random-access}@; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...); + + friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); + + friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires (@\libconcept{indirectly_swappable}@>> && ...); + }; +} +\end{codeblock} + +\pnum +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +\begin{itemize} +\item +If \tcode{\exposconcept{all-random-access}} is modeled, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, +if \tcode{\exposconcept{all-bidirectional}} is modeled, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, +if \tcode{\exposconcept{all-forward}} is modeled, +then \tcode{iterator_concept} denotes \tcode{for\-ward_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\pnum +\tcode{\exposid{iterator}::iterator_category} is present +if and only if \tcode{\exposconcept{all-forward}} is modeled. + +\pnum +If the invocation of any non-const member function of \exposid{iterator} +exits via an exception, +the iterator acquires a singular value. + +\indexlibraryctor{zip_view::\exposid{iterator}}% \begin{itemdecl} -constexpr difference_type index() const noexcept; +constexpr explicit @\exposid{iterator}@(tuple>...> current); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{pos_};} +Initializes \exposid{current_} with \tcode{std::move(current)}. \end{itemdescr} -\indexlibrarymember{operator++}{enumerate_view::\exposid{iterator}}% +\indexlibraryctor{zip_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && (@\libconcept{convertible_to}@, iterator_t> && ...); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +\end{itemdescr} + +\indexlibrarymember{operator*}{izip_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr auto operator*() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{izip_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -9726,13 +11576,12 @@ \effects Equivalent to: \begin{codeblock} -++@\exposid{current_}@; -++@\exposid{pos_}@; +@\exposid{tuple-for-each}@([](auto& i) { ++i; }, @\exposid{current_}@); return *this; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{operator++}{izip_view::\exposid{iterator}}% \begin{itemdecl} constexpr void operator++(int); \end{itemdecl} @@ -9743,9 +11592,40 @@ Equivalent to \tcode{++*this}. \end{itemdescr} -\indexlibrarymember{operator++}{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{operator++}{izip_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) requires @\exposconcept{all-forward}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{izip_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() requires @\exposconcept{all-bidirectional}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{tuple-for-each}@([](auto& i) { --i; }, @\exposid{current_}@); +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{izip_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator--(int) requires @\exposconcept{all-bidirectional}@; \end{itemdecl} \begin{itemdescr} @@ -9753,15 +11633,16 @@ \effects Equivalent to: \begin{codeblock} -auto temp = *this; -++*this; -return temp; +auto tmp = *this; +--*this; +return tmp; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator--}{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{operator+=}{izip_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -9769,15 +11650,15 @@ \effects Equivalent to: \begin{codeblock} ---@\exposid{current_}@; ---@\exposid{pos_}@; +@\exposid{tuple-for-each}@([&](I& i) { i += iter_difference_t(x); }, @\exposid{current_}@); return *this; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator--}{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{operator-=}{izip_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -9785,16 +11666,15 @@ \effects Equivalent to: \begin{codeblock} -auto temp = *this; ---*this; -return temp; +@\exposid{tuple-for-each}@([&](I& i) { i -= iter_difference_t(x); }, @\exposid{current_}@); +return *this; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+=}{enumerate_view::\exposid{iterator}}% +\indexlibrarymember{operator[]}{izip_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr auto operator[](difference_type n) const + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -9802,55 +11682,70 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{current_}@ += n; -@\exposid{pos_}@ += n; -return *this; +return @\exposid{tuple-transform}@([&](I& i) -> decltype(auto) { + return i[iter_difference_t(n)]; +}, @\exposid{current_}@); \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator-=}{enumerate_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{equality_comparable}@>> && ...); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{current_}@ -= n; -@\exposid{pos_}@ -= n; -return *this; -\end{codeblock} +\returns +\begin{itemize} +\item +\tcode{x.\exposid{current_} == y.\exposid{current_}} +if \tcode{\exposconcept{all-bidirectional}} is \tcode{true}. +\item +Otherwise, \tcode{true} +if there exists an integer $0 \leq i < \tcode{sizeof...(Views)}$ +such that \tcode{bool(std::\brk{}get<$i$>(x.\exposid{current_}) == +std::get<$i$>(y.\exposid{current_}))} is \tcode{true}. +\begin{note} +This allows \tcode{zip_view} to model \libconcept{common_range} +when all constituent views model \libconcept{common_range}. +\end{note} +\item +Otherwise, \tcode{false}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{operator==}{enumerate_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{pos_} == y.\exposid{pos_};} +\returns +\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. \end{itemdescr} -\indexlibrarymember{operator<=>}{enumerate_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr strong_ordering operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) + requires @\exposconcept{all-random-access}@; +friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{pos_} <=> y.\exposid{pos_};} +Equivalent to: +\begin{codeblock} +auto r = i; +r += n; +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+}{enumerate_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -9858,28 +11753,30 @@ \effects Equivalent to: \begin{codeblock} -auto temp = x; -temp += y; -return temp; +auto r = i; +r -= n; +return r; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+}{enumerate_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return y + x;} +Let \tcode{\exposid{DIST}($i$)} be \tcode{difference_type(std::get<$i$>(x.\exposid{current_}) - std::get<$i$>(y.\exposid{current_}))}. + +\pnum +\returns +The value with the smallest absolute value among \tcode{\exposid{DIST}($n$)} +for all integers $0 \leq n < \tcode{sizeof...(Views)}$. \end{itemdescr} -\indexlibrarymember{operator-}{enumerate_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -9887,396 +11784,419 @@ \effects Equivalent to: \begin{codeblock} -auto temp = x; -temp -= y; -return temp; +return @\exposid{tuple-transform}@(ranges::iter_move, i.@\exposid{current_}@); +\end{codeblock} + +\pnum +\remarks +The exception specification is equivalent to: +\begin{codeblock} +(noexcept(ranges::iter_move(declval>&>())) && ...) && +(is_nothrow_move_constructible_v>> && ...) \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator-}{enumerate_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept; +friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires (@\libconcept{indirectly_swappable}@>> && ...); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{pos_} - y.\exposid{pos_};} +For every integer $0 \leq i < \tcode{sizeof...(Views)}$, +performs: +\begin{codeblock} +ranges::iter_swap(std::get<@$i$@>(l.@\exposid{current_}@), std::get<@$i$@>(r.@\exposid{current_}@)) +\end{codeblock} + +\pnum +\remarks +The exception specification is equivalent to +the logical \logop{and} of the following expressions: +\begin{codeblock} +noexcept(ranges::iter_swap(std::get<@$i$@>(l.@\exposid{current_}@), std::get<@$i$@>(r.@\exposid{current_}@))) +\end{codeblock} +for every integer $0 \leq i < \tcode{sizeof...(Views)}$. \end{itemdescr} -\rSec3[range.enumerate.sentinel]{Class template \tcode{enumerate_view::\exposid{sentinel}}} +\rSec3[range.zip.sentinel]{Class template \tcode{zip_view::\exposid{sentinel}}} -\indexlibraryglobal{enumerate_view::\exposid{sentinel}}% +\indexlibraryglobal{zip_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\exposconcept{range-with-movable-references}@ + template<@\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) template - class enumerate_view::@\exposid{sentinel}@ { - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - sentinel_t<@\exposidnc{Base}@> @\exposidnc{end_}@ = sentinel_t<@\exposidnc{Base}@>(); // \expos - constexpr explicit @\exposidnc{sentinel}@(sentinel_t<@\exposidnc{Base}@> end); // \expos - + class zip_view::@\exposid{sentinel}@ { + tuple>...> @\exposid{end_}@;@\itcorr[-1]@ // \expos + constexpr explicit @\exposidnc{sentinel}@(tuple>...> end); + // \expos public: @\exposid{sentinel}@() = default; - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; - - constexpr sentinel_t<@\exposid{Base}@> base() const; + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) + requires Const && (@\libconcept{convertible_to}@, sentinel_t> && ...); template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + requires (@\libconcept{sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr range_difference_t<@\exposid{maybe-const}@> + requires (@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) + friend constexpr common_type_t>...> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + requires (@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) + friend constexpr common_type_t>...> + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); }; } \end{codeblock} -\indexlibraryctor{enumerate_view::\exposid{sentinel}}% -\begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{end_} with \tcode{std::move(end)}. -\end{itemdescr} - -\indexlibraryctor{enumerate_view::\exposid{sentinel}}% +\indexlibraryctor{zip_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +constexpr explicit @\exposid{sentinel}@(tuple>...> end); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{std::move(other.\exposid{end_})}. +Initializes \exposid{end_} with \tcode{end}. \end{itemdescr} -\indexlibrarymember{base}{enumerate_view::\exposid{sentinel}}% +\indexlibraryctor{zip_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr sentinel_t<@\exposid{Base}@> base() const; +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) + requires Const && (@\libconcept{convertible_to}@, sentinel_t> && ...); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{end_};} +Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. \end{itemdescr} -\indexlibrarymember{operator==}{enumerate_view::\exposid{sentinel}}% \begin{itemdecl} template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + requires (@\libconcept{sentinel_for}@>, + iterator_t>> && ...) friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} +\returns +\tcode{true} if there exists an integer $0 \leq i < \tcode{sizeof...(Views)}$ +such that \tcode{bool(std::get<$i$>(x.\brk{}\exposid{current_}) == +std::get<$i$>(y.\exposid{end_}))} is \tcode{true}. +Otherwise, \tcode{false}. \end{itemdescr} -\indexlibrarymember{operator-}{enumerate_view::\exposid{sentinel}}% \begin{itemdecl} template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr range_difference_t<@\exposid{maybe-const}@> + requires (@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) +friend constexpr common_type_t>...> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{end_};} +Let \tcode{D} be the return type. +Let \tcode{\exposid{DIST}($i$)} be +\tcode{D(std::get<$i$>(x.\exposid{current_}) - std::get<$i$>(y.\exposid{end_}))}. + +\pnum +\returns +The value with the smallest absolute value among \tcode{\exposid{DIST}($n$)} +for all integers $0 \leq n < \tcode{sizeof...(Views)}$. \end{itemdescr} -\indexlibrarymember{operator-}{enumerate_view::\exposid{sentinel}}% \begin{itemdecl} template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + requires (@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) +friend constexpr common_type_t>...> + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{end_} - y.\exposid{current_};} +Equivalent to: \tcode{return -(x - y);} \end{itemdescr} -\rSec2[range.zip]{Zip view} - -\rSec3[range.zip.overview]{Overview} +\rSec2[range.zip.transform]{Zip transform view} -\pnum -\indexlibraryglobal{zip_view}% -\tcode{zip_view} takes any number of views and -produces a view of tuples of references -to the corresponding elements of the constituent views. +\rSec3[range.zip.transform.overview]{Overview} \pnum -\indexlibrarymember{zip}{views}% -The name \tcode{views::zip} denotes +\indexlibraryglobal{zip_transform_view}% +\tcode{zip_transform_view} takes an invocable object and +any number of views and +produces a view +whose $M^\text{th}$ element is +the result of applying the invocable object +to the $M^\text{th}$ elements of all views. + +\pnum +\indexlibrarymember{zip_transform}{views}% +The name \tcode{views::zip_transform} denotes a customization point object\iref{customization.point.object}. -Given a pack of subexpressions \tcode{Es...}, -the expression \tcode{views::zip(Es...)} is expression-equivalent to +Let \tcode{F} be a subexpression, and +let \tcode{Es...} be a pack of subexpressions. \begin{itemize} \item -\tcode{auto(views::empty>)} -if \tcode{Es} is an empty pack, +If \tcode{Es} is an empty pack, +let \tcode{FD} be \tcode{decay_t}. +\begin{itemize} \item -otherwise, \tcode{zip_view...>(Es...)}. +If \tcode{\libconcept{move_constructible} \&\& +\libconcept{regular_invocable}} is \tcode{false}, or +if \tcode{decay_t>} is not an object type, +\tcode{views::zip_transform(F, Es...)} is ill-formed. +\item +Otherwise, the expression \tcode{views::zip_transform(F, Es...)} +is expression-equivalent to +\begin{codeblock} +((void)F, auto(views::empty>>)) +\end{codeblock} +\end{itemize} +\item +Otherwise, the expression \tcode{views::zip_transform(F, Es...)} +is expression-equivalent to \tcode{zip_trans\-form_view(F, Es...)}. \end{itemize} +\pnum \begin{example} \begin{codeblock} -vector v = {1, 2}; -list l = {'a', 'b', 'c'}; - -auto z = views::zip(v, l); -range_reference_t f = z.front(); // \tcode{f} is a \tcode{tuple} - // that refers to the first element of \tcode{v} and \tcode{l} +vector v1 = {1, 2}; +vector v2 = {4, 5, 6}; -for (auto&& [x, y] : z) { - cout << '(' << x << ", " << y << ") "; // prints \tcode{(1, a) (2, b)} +for (auto i : views::zip_transform(plus(), v1, v2)) { + cout << i << ' '; // prints \tcode{5 7} } \end{codeblock} \end{example} -\rSec3[range.zip.view]{Class template \tcode{zip_view}} +\rSec3[range.zip.transform.view]{Class template \tcode{zip_transform_view}} -\indexlibrarymember{begin}{zip_view}% -\indexlibrarymember{end}{zip_view}% -\indexlibrarymember{size}{zip_view}% +\indexlibraryglobal{zip_transform_view}% +\indexlibrarymember{begin}{zip_transform_view}% +\indexlibrarymember{end}{zip_transform_view}% +\indexlibrarymember{size}{zip_transform_view}% \begin{codeblock} namespace std::ranges { - template - concept @\defexposconcept{zip-is-common}@ = // \expos - (sizeof...(Rs) == 1 && (@\libconcept{common_range}@ && ...)) || - (!(@\libconcept{bidirectional_range}@ && ...) && (@\libconcept{common_range}@ && ...)) || - ((@\libconcept{random_access_range}@ && ...) && (@\libconcept{sized_range}@ && ...)); + template<@\libconcept{move_constructible}@ F, @\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && is_object_v && + @\libconcept{regular_invocable}@...> && + @\exposconcept{can-reference}@...>> + class zip_transform_view : public view_interface> { + @\exposidnc{movable-box}@ @\exposid{fun_}@; // \expos + zip_view @\exposid{zip_}@; // \expos - template<@\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) - class zip_view : public view_interface> { - tuple @\exposid{views_}@; // \expos + using @\exposidnc{InnerView}@ = zip_view; // \expos + template + using @\exposidnc{ziperator}@ = iterator_t<@\exposidnc{maybe-const}@>; // \expos + template + using @\exposidnc{zentinel}@ = sentinel_t<@\exposidnc{maybe-const}@>; // \expos - // \ref{range.zip.iterator}, class template \tcode{zip_view::\exposid{iterator}} - template class @\exposidnc{iterator}@; // \expos + // \ref{range.zip.transform.iterator}, class template \tcode{zip_transform_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos - // \ref{range.zip.sentinel}, class template \tcode{zip_view::\exposid{sentinel}} - template class @\exposidnc{sentinel}@; // \expos + // \ref{range.zip.transform.sentinel}, class template \tcode{zip_transform_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos public: - zip_view() = default; - constexpr explicit zip_view(Views... views); + zip_transform_view() = default; - constexpr auto begin() requires (!(@\exposconcept{simple-view}@ && ...)) { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::begin, @\exposid{views_}@)); - } - constexpr auto begin() const requires (@\libconcept{range}@ && ...) { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::begin, @\exposid{views_}@)); + constexpr explicit zip_transform_view(F fun, Views... views); + + constexpr auto begin() { return @\exposid{iterator}@(*this, @\exposid{zip_}@.begin()); } + + constexpr auto begin() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@...> { + return @\exposid{iterator}@(*this, @\exposid{zip_}@.begin()); } - constexpr auto end() requires (!(@\exposconcept{simple-view}@ && ...)) { - if constexpr (!@\exposconcept{zip-is-common}@) { - return @\exposid{sentinel}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); - } else if constexpr ((@\libconcept{random_access_range}@ && ...)) { - return begin() + iter_difference_t<@\exposid{iterator}@>(size()); + constexpr auto end() { + if constexpr (@\libconcept{common_range}@<@\exposid{InnerView}@>) { + return @\exposid{iterator}@(*this, @\exposid{zip_}@.end()); } else { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + return @\exposid{sentinel}@(@\exposid{zip_}@.end()); } } - constexpr auto end() const requires (@\libconcept{range}@ && ...) { - if constexpr (!@\exposconcept{zip-is-common}@) { - return @\exposid{sentinel}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); - } else if constexpr ((@\libconcept{random_access_range}@ && ...)) { - return begin() + iter_difference_t<@\exposid{iterator}@>(size()); + constexpr auto end() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@...> { + if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@(*this, @\exposid{zip_}@.end()); } else { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + return @\exposid{sentinel}@(@\exposid{zip_}@.end()); } } - constexpr auto size() requires (@\libconcept{sized_range}@ && ...); - constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); + constexpr auto size() requires @\libconcept{sized_range}@<@\exposid{InnerView}@> { + return @\exposid{zip_}@.size(); + } + + constexpr auto size() const requires @\libconcept{sized_range}@ { + return @\exposid{zip_}@.size(); + } }; - template - zip_view(Rs&&...) -> zip_view...>; + template + zip_transform_view(F, Rs&&...) -> zip_transform_view...>; } \end{codeblock} -\pnum -Two \tcode{zip_view} objects have the same underlying sequence if and only if -the corresponding elements of \exposid{views_} are equal\iref{concepts.equality} -and have the same underlying sequence. -\begin{note} -In particular, comparison of iterators obtained from \tcode{zip_view} objects -that do not have the same underlying sequence -is not required to produce meaningful results\iref{iterator.concept.forward}. -\end{note} - -\begin{itemdecl} -constexpr explicit zip_view(Views... views); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{views_} with \tcode{std::move(views)...}. -\end{itemdescr} - +\indexlibraryctor{zip_transform_view}% \begin{itemdecl} -constexpr auto size() requires (@\libconcept{sized_range}@ && ...); -constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); +constexpr explicit zip_transform_view(F fun, Views... views); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return apply([](auto... sizes) { - using CT = @\exposid{make-unsigned-like-t}@>; - return ranges::min({CT(sizes)...}); -}, @\exposid{tuple-transform}@(ranges::size, @\exposid{views_}@)); -\end{codeblock} +Initializes \exposid{fun_} with \tcode{std::move(fun)} and +\exposid{zip_} with \tcode{std::move(views)...}. \end{itemdescr} -\rSec3[range.zip.iterator]{Class template \tcode{zip_view::\exposid{iterator}}} +\rSec3[range.zip.transform.iterator]{Class template \tcode{zip_transform_view::\exposid{iterator}}} +\indexlibraryglobal{zip_transform_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { - template - concept @\defexposconceptnc{all-random-access}@ = // \expos - (@\libconcept{random_access_range}@<@\exposid{maybe-const}@> && ...); - template - concept @\defexposconceptnc{all-bidirectional}@ = // \expos - (@\libconcept{bidirectional_range}@<@\exposid{maybe-const}@> && ...); - template - concept @\defexposconceptnc{all-forward}@ = // \expos - (@\libconcept{forward_range}@<@\exposid{maybe-const}@> && ...); - - template<@\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) + template<@\libconcept{move_constructible}@ F, @\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && is_object_v && + @\libconcept{regular_invocable}@...> && + @\exposconcept{can-reference}@...>> template - class zip_view::@\exposid{iterator}@ { - tuple>...> @\exposid{current_}@;@\itcorr[-1]@ // \expos - constexpr explicit @\exposidnc{iterator}@(tuple>...>); - // \expos + class zip_transform_view::@\exposid{iterator}@ { + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + @\exposid{ziperator}@ @\exposid{inner_}@;@\itcorr[-1]@ // \expos + + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); // \expos + public: - using iterator_category = input_iterator_tag; // not always present - using iterator_concept = @\seebelow@; - using value_type = tuple>...>; - using difference_type = common_type_t>...>; + using iterator_category = @\seebelownc@; // not always present + using iterator_concept = typename @\exposid{ziperator}@::iterator_concept; + using value_type = + remove_cvref_t&, + range_reference_t<@\exposid{maybe-const}@>...>>; + using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{iterator}@() = default; constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && (@\libconcept{convertible_to}@, iterator_t> && ...); + requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; - constexpr auto operator*() const; + constexpr decltype(auto) operator*() const noexcept(@\seebelow@); constexpr @\exposid{iterator}@& operator++(); constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\exposconcept{all-forward}@; + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator--() requires @\exposconcept{all-bidirectional}@; - constexpr @\exposid{iterator}@ operator--(int) requires @\exposconcept{all-bidirectional}@; + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\exposconcept{all-random-access}@; - constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\exposconcept{all-random-access}@; + constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr auto operator[](difference_type n) const - requires @\exposconcept{all-random-access}@; + constexpr decltype(auto) operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires (@\libconcept{equality_comparable}@>> && ...); + requires @\libconcept{equality_comparable}@<@\exposid{ziperator}@>; friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires (@\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ...); - - friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); - - friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) - requires (@\libconcept{indirectly_swappable}@>> && ...); + requires @\libconcept{sized_sentinel_for}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; }; } \end{codeblock} \pnum -\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +The member \grammarterm{typedef-name} +\tcode{\exposid{iterator}::iterator_category} +is defined if and only if \exposid{Base} models \libconcept{forward_range}. +In that case, +\tcode{\exposid{iterator}::iterator_category} is defined as follows: +\begin{itemize} +\item +If +\begin{codeblock} +invoke_result_t<@\exposid{maybe-const}@&, range_reference_t<@\exposid{maybe-const}@>...> +\end{codeblock} +is not a reference, +\tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\item +Otherwise, let \tcode{Cs} denote the pack of types +\tcode{iterator_traits>>::iterator_category...}. \begin{itemize} \item -If \tcode{\exposconcept{all-random-access}} is modeled, -then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +If \tcode{(\libconcept{derived_from} \&\& ...)} +is \tcode{true}, +\tcode{iterator_category} denotes \tcode{random_access_iterator_tag}. \item Otherwise, -if \tcode{\exposconcept{all-bidirectional}} is modeled, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +if \tcode{(\libconcept{derived_from} \&\& ...)} +is \tcode{true}, +\tcode{iterator\-_category} denotes \tcode{bidirectional_iterator_tag}. \item Otherwise, -if \tcode{\exposconcept{all-forward}} is modeled, -then \tcode{iterator_concept} denotes \tcode{for\-ward_iterator_tag}. +if \tcode{(\libconcept{derived_from} \&\& ...)} +is \tcode{true}, +\tcode{iterator_cate\-gory} denotes \tcode{forward_iterator_tag}. \item -Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\end{itemize} \end{itemize} -\pnum -\tcode{\exposid{iterator}::iterator_category} is present -if and only if \tcode{\exposconcept{all-forward}} is modeled. - -\pnum -If the invocation of any non-const member function of \exposid{iterator} -exits via an exception, -the iterator acquires a singular value. - +\indexlibraryctor{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{iterator}@(tuple>...> current); +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(current)}. +Initializes \exposid{parent_} with \tcode{addressof(parent)} and +\exposid{inner_} with \tcode{std::move(inner)}. \end{itemdescr} +\indexlibraryctor{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && (@\libconcept{convertible_to}@, iterator_t> && ...); + requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and +\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. \end{itemdescr} +\indexlibrarymember{operator*}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr auto operator*() const; +constexpr decltype(auto) operator*() const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -10284,10 +12204,19 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); +return apply([&](const auto&... iters) -> decltype(auto) { + return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *iters...); +}, @\exposid{inner_}@.@\exposid{current_}@); \end{codeblock} + +\pnum +\remarks +Let \tcode{Is} be the pack \tcode{0, 1, \ldots, \tcode{(sizeof...(Views) - 1)}}. +The exception specification is equivalent to: +\tcode{noexcept(invoke(*\exposid{parent_}->\exposid{fun_}, *std::get(\exposid{inner_}.\exposid{current_})...))}. \end{itemdescr} +\indexlibrarymember{operator++}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -10297,11 +12226,12 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{tuple-for-each}@([](auto& i) { ++i; }, @\exposid{current_}@); +++@\exposid{inner_}@; return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} constexpr void operator++(int); \end{itemdecl} @@ -10309,11 +12239,12 @@ \begin{itemdescr} \pnum \effects -Equivalent to \tcode{++*this}. +Equivalent to: \tcode{++*this}. \end{itemdescr} +\indexlibrarymember{operator++}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\exposconcept{all-forward}@; +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -10327,8 +12258,9 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\exposconcept{all-bidirectional}@; +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -10336,13 +12268,14 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{tuple-for-each}@([](auto& i) { --i; }, @\exposid{current_}@); +--@\exposid{inner_}@; return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\exposconcept{all-bidirectional}@; +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -10356,9 +12289,10 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -10366,14 +12300,15 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{tuple-for-each}@([&](I& i) { i += iter_difference_t(x); }, @\exposid{current_}@); +@\exposid{inner_}@ += x; return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -10381,14 +12316,15 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{tuple-for-each}@([&](I& i) { i -= iter_difference_t(x); }, @\exposid{current_}@); +@\exposid{inner_}@ -= x; return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator[]}{zip_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr auto operator[](difference_type n) const - requires @\exposconcept{all-random-access}@; +constexpr decltype(auto) operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -10396,437 +12332,356 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{tuple-transform}@([&](I& i) -> decltype(auto) { - return i[iter_difference_t(n)]; -}, @\exposid{current_}@); +return apply([&](const Is&... iters) -> decltype(auto) { + return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, iters[iter_difference_t(n)]...); +}, @\exposid{inner_}@.@\exposid{current_}@); \end{codeblock} \end{itemdescr} \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires (@\libconcept{equality_comparable}@>> && ...); + requires @\libconcept{equality_comparable}@<@\exposid{ziperator}@>; +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\begin{itemize} -\item -\tcode{x.\exposid{current_} == y.\exposid{current_}} -if \tcode{\exposconcept{all-bidirectional}} is \tcode{true}. -\item -Otherwise, \tcode{true} -if there exists an integer $0 \leq i < \tcode{sizeof...(Views)}$ -such that \tcode{bool(std::\brk{}get<$i$>(x.\exposid{current_}) == -std::get<$i$>(y.\exposid{current_}))} is \tcode{true}. -\begin{note} -This allows \tcode{zip_view} to model \libconcept{common_range} -when all constituent views model \libconcept{common_range}. -\end{note} -\item -Otherwise, \tcode{false}. -\end{itemize} -\end{itemdescr} - -\begin{itemdecl} -friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; -\end{itemdecl} +Let \placeholder{op} be the operator. -\begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. +\effects +Equivalent to: +\tcode{return x.\exposid{inner_} \placeholder{op} y.\exposid{inner_};} \end{itemdescr} \begin{itemdecl} friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: -\begin{codeblock} -auto r = i; -r += n; -return r; -\end{codeblock} +\tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} + n);} \end{itemdescr} \begin{itemdecl} friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: -\begin{codeblock} -auto r = i; -r -= n; -return r; -\end{codeblock} +\tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} - n);} \end{itemdescr} \begin{itemdecl} friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires (@\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ...); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{\exposid{DIST}($i$)} be \tcode{difference_type(std::get<$i$>(x.\exposid{current_}) - std::get<$i$>(y.\exposid{current_}))}. - -\pnum -\returns -The value with the smallest absolute value among \tcode{\exposid{DIST}($n$)} -for all integers $0 \leq n < \tcode{sizeof...(Views)}$. -\end{itemdescr} - -\begin{itemdecl} -friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); + requires @\libconcept{sized_sentinel_for}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: -\begin{codeblock} -return @\exposid{tuple-transform}@(ranges::iter_move, i.@\exposid{current_}@); -\end{codeblock} - -\pnum -\remarks -The exception specification is equivalent to: -\begin{codeblock} -(noexcept(ranges::iter_move(declval>&>())) && ...) && -(is_nothrow_move_constructible_v>> && ...) -\end{codeblock} -\end{itemdescr} - -\begin{itemdecl} -friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) - requires (@\libconcept{indirectly_swappable}@>> && ...); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -For every integer $0 \leq i < \tcode{sizeof...(Views)}$, -performs: -\begin{codeblock} -ranges::iter_swap(std::get<@$i$@>(l.@\exposid{current_}@), std::get<@$i$@>(r.@\exposid{current_}@)) -\end{codeblock} - -\pnum -\remarks -The exception specification is equivalent to -the logical \logop{and} of the following expressions: -\begin{codeblock} -noexcept(ranges::iter_swap(std::get<@$i$@>(l.@\exposid{current_}@), std::get<@$i$@>(r.@\exposid{current_}@))) -\end{codeblock} -for every integer $0 \leq i < \tcode{sizeof...(Views)}$. +\tcode{return x.\exposid{inner_} - y.\exposid{inner_};} \end{itemdescr} -\rSec3[range.zip.sentinel]{Class template \tcode{zip_view::\exposid{sentinel}}} +\rSec3[range.zip.transform.sentinel]{Class template \tcode{zip_transform_view::\exposid{sentinel}}} +\indexlibraryglobal{zip_transform_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) + template<@\libconcept{move_constructible}@ F, @\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && is_object_v && + @\libconcept{regular_invocable}@...> && + @\exposconcept{can-reference}@...>> template - class zip_view::@\exposid{sentinel}@ { - tuple>...> @\exposid{end_}@;@\itcorr[-1]@ // \expos - constexpr explicit @\exposidnc{sentinel}@(tuple>...> end); - // \expos + class zip_transform_view::@\exposid{sentinel}@ { + @\exposidnc{zentinel}@ @\exposid{inner_}@; // \expos + constexpr explicit @\exposidnc{sentinel}@(@\exposidnc{zentinel}@ inner); // \expos + public: @\exposid{sentinel}@() = default; constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && (@\libconcept{convertible_to}@, sentinel_t> && ...); + requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; template - requires (@\libconcept{sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ...) + requires @\libconcept{sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires (@\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ...) - friend constexpr common_type_t>...> + requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> + friend constexpr range_difference_t<@\exposid{maybe-const}@> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires (@\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ...) - friend constexpr common_type_t>...> - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); + requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> + friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); }; } \end{codeblock} +\indexlibraryctor{zip_transform_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(tuple>...> end); +constexpr explicit @\exposid{sentinel}@(@\exposid{zentinel}@ inner); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end}. +Initializes \exposid{inner_} with \tcode{inner}. \end{itemdescr} +\indexlibraryctor{zip_transform_view::\exposid{sentinel}}% \begin{itemdecl} constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && (@\libconcept{convertible_to}@, sentinel_t> && ...); + requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. -\end{itemdescr} - -\begin{itemdecl} -template - requires (@\libconcept{sentinel_for}@>, - iterator_t>> && ...) -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if there exists an integer $0 \leq i < \tcode{sizeof...(Views)}$ -such that \tcode{bool(std::get<$i$>(x.\brk{}\exposid{current_}) == -std::get<$i$>(y.\exposid{end_}))} is \tcode{true}. -Otherwise, \tcode{false}. +Initializes \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. \end{itemdescr} - -\begin{itemdecl} -template - requires (@\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ...) -friend constexpr common_type_t>...> - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + +\begin{itemdecl} +template + requires @\libconcept{sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{D} be the return type. -Let \tcode{\exposid{DIST}($i$)} be -\tcode{D(std::get<$i$>(x.\exposid{current_}) - std::get<$i$>(y.\exposid{end_}))}. - -\pnum -\returns -The value with the smallest absolute value among \tcode{\exposid{DIST}($n$)} -for all integers $0 \leq n < \tcode{sizeof...(Views)}$. +\effects +Equivalent to: \tcode{return x.\exposid{inner_} == y.\exposid{inner_};} \end{itemdescr} \begin{itemdecl} template - requires (@\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ...) -friend constexpr common_type_t>...> - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); + requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +template + requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return -(x - y);} +Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} \end{itemdescr} -\rSec2[range.zip.transform]{Zip transform view} +\rSec2[range.adjacent]{Adjacent view} -\rSec3[range.zip.transform.overview]{Overview} +\rSec3[range.adjacent.overview]{Overview} \pnum -\indexlibraryglobal{zip_transform_view}% -\tcode{zip_transform_view} takes an invocable object and -any number of views and -produces a view -whose $M^\text{th}$ element is -the result of applying the invocable object -to the $M^\text{th}$ elements of all views. +\tcode{adjacent_view} takes a view and +produces a view whose $M^\text{th}$ element is +a tuple of references to +the $M^\text{th}$ through $(M + N - 1)^\text{th}$ elements of +the original view. +If the original view has fewer than $N$ elements, the resulting view is empty. \pnum -\indexlibrarymember{zip_transform}{views}% -The name \tcode{views::zip_transform} denotes -a customization point object\iref{customization.point.object}. -Let \tcode{F} be a subexpression, and -let \tcode{Es...} be a pack of subexpressions. -\begin{itemize} -\item -If \tcode{Es} is an empty pack, -let \tcode{FD} be \tcode{decay_t}. +\indexlibrarymember{adjacent}{views}% +The name \tcode{views::adjacent} denotes +a range adaptor object\iref{range.adaptor.object}. +Given a subexpression \tcode{E} and a constant expression \tcode{N}, +the expression \tcode{views::adjacent(E)} is expression-equivalent to \begin{itemize} \item -If \tcode{\libconcept{move_constructible} \&\& -\libconcept{regular_invocable}} is \tcode{false}, or -if \tcode{decay_t>} is not an object type, -\tcode{views::zip_transform(F, Es...)} is ill-formed. -\item -Otherwise, the expression \tcode{views::zip_transform(F, Es...)} -is expression-equivalent to -\begin{codeblock} -((void)F, auto(views::empty>>)) -\end{codeblock} -\end{itemize} +\tcode{((void)E, auto(views::empty>))} +if \tcode{N} is equal to \tcode{0} and +\tcode{decltype((E))} models \libconcept{forward_range}, \item -Otherwise, the expression \tcode{views::zip_transform(F, Es...)} -is expression-equivalent to \tcode{zip_trans\-form_view(F, Es...)}. +otherwise, \tcode{adjacent_view, N>(E)}. \end{itemize} -\pnum \begin{example} \begin{codeblock} -vector v1 = {1, 2}; -vector v2 = {4, 5, 6}; +vector v = {1, 2, 3, 4}; -for (auto i : views::zip_transform(plus(), v1, v2)) { - cout << i << ' '; // prints \tcode{5 7} +for (auto i : v | views::adjacent<2>) { + cout << "(" << std::get<0>(i) << ", " << std::get<1>(i) << ") "; // prints \tcode{(1, 2) (2, 3) (3, 4)} } \end{codeblock} \end{example} -\rSec3[range.zip.transform.view]{Class template \tcode{zip_transform_view}} +\pnum +Define \tcode{\exposid{REPEAT}(T, N)} as a pack of \tcode{N} types, +each of which denotes the same type as \tcode{T}. -\indexlibrarymember{begin}{zip_transform_view}% -\indexlibrarymember{end}{zip_transform_view}% -\indexlibrarymember{size}{zip_transform_view}% +\rSec3[range.adjacent.view]{Class template \tcode{adjacent_view}} + +\indexlibraryglobal{adjacent_view}% +\indexlibrarymember{begin}{adjacent_view}% +\indexlibrarymember{end}{adjacent_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{move_constructible}@ F, @\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && is_object_v && - @\libconcept{regular_invocable}@...> && - @\exposconcept{can-reference}@...>> - class zip_transform_view : public view_interface> { - @\exposidnc{movable-box}@ @\exposid{fun_}@; // \expos - zip_view @\exposid{zip_}@; // \expos + template<@\libconcept{forward_range}@ V, size_t N> + requires @\libconcept{view}@ && (N > 0) + class adjacent_view : public view_interface> { + V @\exposid{base_}@ = V(); // \expos - using @\exposidnc{InnerView}@ = zip_view; // \expos - template - using @\exposidnc{ziperator}@ = iterator_t<@\exposidnc{maybe-const}@>; // \expos - template - using @\exposidnc{zentinel}@ = sentinel_t<@\exposidnc{maybe-const}@>; // \expos + // \ref{range.adjacent.iterator}, class template \tcode{adjacent_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos - // \ref{range.zip.transform.iterator}, class template \tcode{zip_transform_view::\exposid{iterator}} - template class @\exposidnc{iterator}@; // \expos + // \ref{range.adjacent.sentinel}, class template \tcode{adjacent_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos - // \ref{range.zip.transform.sentinel}, class template \tcode{zip_transform_view::\exposid{sentinel}} - template class @\exposidnc{sentinel}@; // \expos + struct @\exposidnc{as-sentinel}@{}; // \expos public: - zip_transform_view() = default; + adjacent_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit adjacent_view(V base); - constexpr explicit zip_transform_view(F fun, Views... views); + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } - constexpr auto begin() { return @\exposid{iterator}@(*this, @\exposid{zip_}@.begin()); } + constexpr auto begin() requires (!@\exposconcept{simple-view}@) { + return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + } - constexpr auto begin() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@...> { - return @\exposid{iterator}@(*this, @\exposid{zip_}@.begin()); + constexpr auto begin() const requires @\libconcept{range}@ { + return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); } - constexpr auto end() { - if constexpr (@\libconcept{common_range}@<@\exposid{InnerView}@>) { - return @\exposid{iterator}@(*this, @\exposid{zip_}@.end()); + constexpr auto end() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@(@\exposid{as-sentinel}@{}, ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); } else { - return @\exposid{sentinel}@(@\exposid{zip_}@.end()); + return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); } } - constexpr auto end() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@...> { - if constexpr (@\libconcept{common_range}@) { - return @\exposid{iterator}@(*this, @\exposid{zip_}@.end()); + constexpr auto end() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@(@\exposid{as-sentinel}@{}, ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); } else { - return @\exposid{sentinel}@(@\exposid{zip_}@.end()); + return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); } } - constexpr auto size() requires @\libconcept{sized_range}@<@\exposid{InnerView}@> { - return @\exposid{zip_}@.size(); - } + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; - constexpr auto size() const requires @\libconcept{sized_range}@ { - return @\exposid{zip_}@.size(); - } + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; }; - - template - zip_transform_view(F, Rs&&...) -> zip_transform_view...>; } \end{codeblock} +\indexlibraryctor{adjacent_view}% \begin{itemdecl} -constexpr explicit zip_transform_view(F fun, Views... views); +constexpr explicit adjacent_view(V base); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{fun_} with \tcode{std::move(fun)} and -\exposid{zip_} with \tcode{std::move(views)...}. +Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\rSec3[range.zip.transform.iterator]{Class template \tcode{zip_transform_view::\exposid{iterator}}} +\indexlibrarymember{size}{adjacent_view}% +\begin{itemdecl} +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{move_constructible}@ F, @\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && is_object_v && - @\libconcept{regular_invocable}@...> && - @\exposconcept{can-reference}@...>> - template - class zip_transform_view::@\exposid{iterator}@ { - using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos - @\exposid{ziperator}@ @\exposid{inner_}@;@\itcorr[-1]@ // \expos +using ST = decltype(ranges::size(@\exposid{base_}@)); +using CT = common_type_t; +auto sz = static_cast(ranges::size(@\exposid{base_}@)); +sz -= std::min(sz, N - 1); +return static_cast(sz); +\end{codeblock} +\end{itemdescr} - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); // \expos +\indexlibrarymember{reserve_hint}{adjacent_view}% +\begin{itemdecl} +constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; +constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +using DT = range_difference_t; +using CT = common_type_t; +auto sz = static_cast(ranges::reserve_hint(@\exposid{base_}@)); +sz -= std::min(sz, N - 1); +return @\exposid{to-unsigned-like}@(sz); +\end{codeblock} +\end{itemdescr} + +\rSec3[range.adjacent.iterator]{Class template \tcode{adjacent_view::\exposid{iterator}}} +\indexlibraryglobal{adjacent_view::\exposid{iterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{forward_range}@ V, size_t N> + requires @\libconcept{view}@ && (N > 0) + template + class adjacent_view::@\exposid{iterator}@ { + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + array, N> @\exposid{current_}@ = array, N>(); // \expos + constexpr @\exposidnc{iterator}@(iterator_t<@\exposidnc{Base}@> first, sentinel_t<@\exposidnc{Base}@> last); // \expos + constexpr @\exposidnc{iterator}@(@\exposidnc{as-sentinel}@, iterator_t<@\exposidnc{Base}@> first, iterator_t<@\exposidnc{Base}@> last); + // \expos public: - using iterator_category = @\seebelownc@; // not always present - using iterator_concept = typename @\exposid{ziperator}@::iterator_concept; - using value_type = - remove_cvref_t&, - range_reference_t<@\exposid{maybe-const}@>...>>; + using iterator_category = input_iterator_tag; + using iterator_concept = @\seebelow@; + using value_type = tuple<@\exposid{REPEAT}@(range_value_t<@\exposid{Base}@>, N)...>; using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{iterator}@() = default; constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; - constexpr decltype(auto) operator*() const noexcept(@\seebelow@); + constexpr auto operator*() const; constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@ operator++(int); constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr decltype(auto) operator[](difference_type n) const + constexpr auto operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); + friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@<@\exposid{ziperator}@>; - friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && + @\libconcept{three_way_comparable}@>; friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -10835,94 +12690,78 @@ friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + + friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); + friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires @\libconcept{indirectly_swappable}@>; }; } \end{codeblock} \pnum -The member \grammarterm{typedef-name} -\tcode{\exposid{iterator}::iterator_category} -is defined if and only if \exposid{Base} models \libconcept{forward_range}. -In that case, -\tcode{\exposid{iterator}::iterator_category} is defined as follows: -\begin{itemize} -\item -If -\begin{codeblock} -invoke_result_t<@\exposid{maybe-const}@&, range_reference_t<@\exposid{maybe-const}@>...> -\end{codeblock} -is not a reference, -\tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\item -Otherwise, let \tcode{Cs} denote the pack of types -\tcode{iterator_traits>>::iterator_category...}. +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: \begin{itemize} \item -If \tcode{(\libconcept{derived_from} \&\& ...)} -is \tcode{true}, -\tcode{iterator_category} denotes \tcode{random_access_iterator_tag}. -\item -Otherwise, -if \tcode{(\libconcept{derived_from} \&\& ...)} -is \tcode{true}, -\tcode{iterator\-_category} denotes \tcode{bidirectional_iterator_tag}. +If \exposid{Base} models \libconcept{random_access_range}, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. \item -Otherwise, -if \tcode{(\libconcept{derived_from} \&\& ...)} -is \tcode{true}, -\tcode{iterator_cate\-gory} denotes \tcode{forward_iterator_tag}. +Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. \item -Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\end{itemize} +Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. \end{itemize} +\pnum +If the invocation of any non-const member function of \exposid{iterator} +exits via an exception, the \exposid{iterator} acquires a singular value. + +\indexlibraryctor{adjacent_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); +constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> first, sentinel_t<@\exposid{Base}@> last); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{parent_} with \tcode{addressof(parent)} and -\exposid{inner_} with \tcode{std::move(inner)}. +\ensures +\tcode{\exposid{current_}[0] == first} is \tcode{true}, and +for every integer $1 \leq i < \tcode{N}$, +\tcode{\exposid{current_}[$i$] == ranges::next(\exposid{current_}[$i$-1], 1, last)} +is \tcode{true}. \end{itemdescr} +\indexlibraryctor{adjacent_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; +constexpr @\exposid{iterator}@(@\exposid{as-sentinel}@, iterator_t<@\exposid{Base}@> first, iterator_t<@\exposid{Base}@> last); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and -\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. +\ensures +If \exposid{Base} does not model \libconcept{bidirectional_range}, +each element of \exposid{current_} is equal to \exposid{last}. +Otherwise, \tcode{\exposid{current_}[N-1] == last} is \tcode{true}, and +for every integer $0 \leq i < (\tcode{N} - 1)$, +\tcode{\exposid{current_}[$i$] == ranges::prev(\exposid{current_}[$i$+1], 1, first)} +is \tcode{true}. \end{itemdescr} +\indexlibraryctor{adjacent_view::\exposid{iterator}}% \begin{itemdecl} -constexpr decltype(auto) operator*() const noexcept(@\seebelow@); +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return apply([&](const auto&... iters) -> decltype(auto) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *iters...); -}, @\exposid{inner_}@.@\exposid{current_}@); -\end{codeblock} - -\pnum -\remarks -Let \tcode{Is} be the pack \tcode{0, 1, \ldots, \tcode{(sizeof...(Views)-1)}}. -The exception specification is equivalent to: -\tcode{noexcept(invoke(*\exposid{parent_}->\exposid{fun_}, *std::get(\exposid{inner_}.\exposid{current_})...))}. +Initializes each element of \exposid{current_} +with the corresponding element of \tcode{i.\exposid{current_}} as an xvalue. \end{itemdescr} +\indexlibrarymember{operator*}{adjacent_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +constexpr auto operator*() const; \end{itemdecl} \begin{itemdescr} @@ -10930,23 +12769,33 @@ \effects Equivalent to: \begin{codeblock} -++@\exposid{inner_}@; -return *this; +return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{adjacent_view::\exposid{iterator}}% \begin{itemdecl} -constexpr void operator++(int); +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{++*this}. +\expects +\tcode{\exposid{current_}.back()} is incrementable. + +\pnum +\ensures +Each element of \exposid{current_} is equal to \tcode{ranges::next(i)}, +where \tcode{i} is the value of that element before the call. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator++}{adjacent_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} \begin{itemdescr} @@ -10960,20 +12809,27 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{adjacent_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} ---@\exposid{inner_}@; -return *this; -\end{codeblock} +\expects +\tcode{\exposid{current_}.front()} is decrementable. + +\pnum +\ensures +Each element of \exposid{current_} is equal to \tcode{ranges::prev(i)}, +where \tcode{i} is the value of that element before the call. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator--}{adjacent_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} @@ -10989,6 +12845,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{adjacent_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -10996,347 +12853,486 @@ \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{inner_}@ += x; -return *this; -\end{codeblock} +\expects +\tcode{\exposid{current_}.back() + x} has well-defined behavior. + +\pnum +\ensures +Each element of \exposid{current_} is equal to \tcode{i + x}, +where \tcode{i} is the value of that element before the call. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator-=}{adjacent_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{current_}.front() - x} has well-defined behavior. + +\pnum +\ensures +Each element of \exposid{current_} is equal to \tcode{i - x}, +where \tcode{i} is the value of that element before the call. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator[]}{adjacent_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr auto operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} -@\exposid{inner_}@ -= x; -return *this; +return @\exposid{tuple-transform}@([&](auto& i) -> decltype(auto) { return i[n]; }, @\exposid{current_}@); \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr decltype(auto) operator[](difference_type n) const +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_}.back() == y.\exposid{current_}.back()}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_}.back() < y.\exposid{current_}.back()}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return apply([&](const Is&... iters) -> decltype(auto) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, iters[iter_difference_t(n)]...); -}, @\exposid{inner_}@.@\exposid{current_}@); -\end{codeblock} +Equivalent to: \tcode{return y < x;} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return !(y < x);} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return !(x < y);} \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@<@\exposid{ziperator}@>; friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && + @\libconcept{three_way_comparable}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_}.back() <=> y.\exposid{current_}.back()}. +\end{itemdescr} + +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -Let \placeholder{op} be the operator. +\effects +Equivalent to: +\begin{codeblock} +auto r = i; +r += n; +return r; +\end{codeblock} +\end{itemdescr} +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} \pnum \effects Equivalent to: -\tcode{return x.\exposid{inner_} \placeholder{op} y.\exposid{inner_};} +\begin{codeblock} +auto r = i; +r -= n; +return r; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: -\tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} + n);} +\tcode{return x.\exposid{current_}.back() - y.\exposid{current_}.back();} \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: -\tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} - n);} +\tcode{return \exposid{tuple-transform}(ranges::iter_move, i.\exposid{current_});} + +\pnum +\remarks +The exception specification is equivalent to: +\begin{codeblock} +noexcept(ranges::iter_move(declval&>())) && +is_nothrow_move_constructible_v> +\end{codeblock} \end{itemdescr} \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; +friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires @\libconcept{indirectly_swappable}@>; \end{itemdecl} \begin{itemdescr} +\pnum +\expects +None of the iterators in \tcode{l.\exposid{current_}} is equal to +an iterator in \tcode{r.\exposid{current_}}. + \pnum \effects -Equivalent to: -\tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +For every integer $0 \leq i < \tcode{N}$, +performs +\tcode{ranges::iter_swap(l.\exposid{current_}[$i$], r.\exposid{current_}[$i$])}. + +\pnum +\remarks +The exception specification is equivalent to: +\begin{codeblock} +noexcept(ranges::iter_swap(declval>(), declval>())) +\end{codeblock} \end{itemdescr} -\rSec3[range.zip.transform.sentinel]{Class template \tcode{zip_transform_view::\exposid{sentinel}}} +\rSec3[range.adjacent.sentinel]{Class template \tcode{adjacent_view::\exposid{sentinel}}} +\indexlibraryglobal{adjacent_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{move_constructible}@ F, @\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) && is_object_v && - @\libconcept{regular_invocable}@...> && - @\exposconcept{can-reference}@...>> + template<@\libconcept{forward_range}@ V, size_t N> + requires @\libconcept{view}@ && (N > 0) template - class zip_transform_view::@\exposid{sentinel}@ { - @\exposidnc{zentinel}@ @\exposid{inner_}@; // \expos - constexpr explicit @\exposidnc{sentinel}@(@\exposidnc{zentinel}@ inner); // \expos + class adjacent_view::@\exposid{sentinel}@ { + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); // \expos public: @\exposid{sentinel}@() = default; constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; template - requires @\libconcept{sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> - friend constexpr range_difference_t<@\exposid{maybe-const}@> + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr range_difference_t<@\exposid{maybe-const}@> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> - friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); }; } \end{codeblock} +\indexlibraryctor{adjacent_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(@\exposid{zentinel}@ inner); +constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{inner_} with \tcode{inner}. +Initializes \exposid{end_} with \tcode{end}. \end{itemdescr} +\indexlibraryctor{adjacent_view::\exposid{sentinel}}% \begin{itemdecl} constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. +Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. \end{itemdescr} \begin{itemdecl} template - requires @\libconcept{sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{inner_} == y.\exposid{inner_};} +Equivalent to: \tcode{return x.\exposid{current_}.back() == y.\exposid{end_};} \end{itemdescr} \begin{itemdecl} template - requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> -friend constexpr range_difference_t<@\exposid{maybe-const}@> + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr range_difference_t<@\exposid{maybe-const}@> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_}.back() - y.\exposid{end_};} +\end{itemdescr} + +\begin{itemdecl} template - requires @\libconcept{sized_sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +Equivalent to: \tcode{return y.\exposid{end_} - x.\exposid{current_}.back();} \end{itemdescr} -\rSec2[range.adjacent]{Adjacent view} +\rSec2[range.adjacent.transform]{Adjacent transform view} -\rSec3[range.adjacent.overview]{Overview} +\rSec3[range.adjacent.transform.overview]{Overview} \pnum -\indexlibraryglobal{adjacent_view}% -\tcode{adjacent_view} takes a view and -produces a view whose $M^\text{th}$ element is -a tuple of references to -the $M^\text{th}$ through $(M + N - 1)^\text{th}$ elements of -the original view. +\tcode{adjacent_transform_view} takes an invocable object and +a view and produces a view +whose $M^\text{th}$ element is the result of applying the invocable object +to the $M^\text{th}$ through $(M + N - 1)^\text{th}$ elements +of the original view. If the original view has fewer than $N$ elements, the resulting view is empty. \pnum -\indexlibrarymember{adjacent}{views}% -The name \tcode{views::adjacent} denotes +\indexlibrarymember{adjacent_transform}{views}% +The name \tcode{views::adjacent_transform} denotes a range adaptor object\iref{range.adaptor.object}. -Given a subexpression \tcode{E} and a constant expression \tcode{N}, -the expression \tcode{views::adjacent(E)} is expression-equivalent to +Given subexpressions \tcode{E} and \tcode{F} and +a constant expression \tcode{N}: \begin{itemize} \item -\tcode{((void)E, auto(views::empty>))} -if \tcode{N} is equal to \tcode{0}, +If \tcode{N} is equal to \tcode{0} and +\tcode{decltype((E))} models \libconcept{forward_range}, +\tcode{views::adjacent_transform(E, F)} is expression-equivalent to +\tcode{((void)E, views::zip_transform(F))}, +except that the evaluations of \tcode{E} and \tcode{F} are +indeterminately sequenced. \item -otherwise, \tcode{adjacent_view, N>(E)}. +Otherwise, +the expression \tcode{views::adjacent_transform(E, F)} is +expression-equivalent to +\tcode{adja\-cent_transform_view, decay_t, N>(E, F)}. \end{itemize} +\pnum \begin{example} \begin{codeblock} vector v = {1, 2, 3, 4}; -for (auto i : v | views::adjacent<2>) { - cout << "(" << std::get<0>(i) << ", " << std::get<1>(i) << ") "; // prints \tcode{(1, 2) (2, 3) (3, 4)} +for (auto i : v | views::adjacent_transform<2>(std::multiplies())) { + cout << i << ' '; // prints \tcode{2 6 12} } \end{codeblock} \end{example} -\pnum -Define \tcode{\exposid{REPEAT}(T, N)} as a pack of \tcode{N} types, -each of which denotes the same type as \tcode{T}. - -\rSec3[range.adjacent.view]{Class template \tcode{adjacent_view}} +\rSec3[range.adjacent.transform.view]{Class template \tcode{adjacent_transform_view}} -\indexlibrarymember{begin}{adjacent_view}% -\indexlibrarymember{end}{adjacent_view}% -\indexlibrarymember{size}{adjacent_view}% +\indexlibraryglobal{adjacent_transform_view}% +\indexlibrarymember{base}{adjacent_transform_view}% +\indexlibrarymember{begin}{adjacent_transform_view}% +\indexlibrarymember{end}{adjacent_transform_view}% +\indexlibrarymember{size}{adjacent_transform_view}% +\indexlibrarymember{reserve_hint}{adjacent_transform_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, size_t N> - requires @\libconcept{view}@ && (N > 0) - class adjacent_view : public view_interface> { - V @\exposid{base_}@ = V(); // \expos + template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> + requires @\libconcept{view}@ && (N > 0) && is_object_v && + @\libconcept{regular_invocable}@, N)...> && + @\exposconcept{can-reference}@, N)...>> + class adjacent_transform_view : public view_interface> { + @\exposidnc{movable-box}@ @\exposid{fun_}@; // \expos + adjacent_view @\exposid{inner_}@; // \expos - // \ref{range.adjacent.iterator}, class template \tcode{adjacent_view::\exposid{iterator}} - template class @\exposidnc{iterator}@; // \expos + using @\exposidnc{InnerView}@ = adjacent_view; // \expos + template + using @\exposid{inner-iterator}@ = iterator_t<@\exposid{maybe-const}@>; // \expos + template + using @\exposid{inner-sentinel}@ = sentinel_t<@\exposid{maybe-const}@>; // \expos - // \ref{range.adjacent.sentinel}, class template \tcode{adjacent_view::\exposid{sentinel}} - template class @\exposidnc{sentinel}@; // \expos + // \ref{range.adjacent.transform.iterator}, class template \tcode{adjacent_transform_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos - struct @\exposidnc{as-sentinel}@{}; // \expos + // \ref{range.adjacent.transform.sentinel}, class template \tcode{adjacent_transform_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos public: - adjacent_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit adjacent_view(V base); + adjacent_transform_view() = default; + constexpr explicit adjacent_transform_view(V base, F fun); - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{inner_}@.base(); } + constexpr V base() && { return std::move(@\exposid{inner_}@).base(); } - constexpr auto begin() requires (!@\exposconcept{simple-view}@) { - return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + constexpr auto begin() { + return @\exposid{iterator}@(*this, @\exposid{inner_}@.begin()); } - constexpr auto begin() const requires @\libconcept{range}@ { - return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + constexpr auto begin() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@, N)...> { + return @\exposid{iterator}@(*this, @\exposid{inner_}@.begin()); } - constexpr auto end() requires (!@\exposconcept{simple-view}@) { - if constexpr (@\libconcept{common_range}@) { - return @\exposid{iterator}@(@\exposid{as-sentinel}@{}, ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + constexpr auto end() { + if constexpr (@\libconcept{common_range}@<@\exposid{InnerView}@>) { + return @\exposid{iterator}@(*this, @\exposid{inner_}@.end()); } else { - return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); + return @\exposid{sentinel}@(@\exposid{inner_}@.end()); } } - constexpr auto end() const requires @\libconcept{range}@ { - if constexpr (@\libconcept{common_range}@) { - return @\exposid{iterator}@(@\exposid{as-sentinel}@{}, ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + constexpr auto end() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@, N)...> { + if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@(*this, @\exposid{inner_}@.end()); } else { - return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); + return @\exposid{sentinel}@(@\exposid{inner_}@.end()); } } - constexpr auto size() requires @\libconcept{sized_range}@; - constexpr auto size() const requires @\libconcept{sized_range}@; + constexpr auto size() requires @\libconcept{sized_range}@<@\exposid{InnerView}@> { + return @\exposid{inner_}@.size(); + } + + constexpr auto size() const requires @\libconcept{sized_range}@ { + return @\exposid{inner_}@.size(); + } + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@<@\exposid{InnerView}@> { + return @\exposid{inner_}@.reserve_hint(); + } + + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@ { + return @\exposid{inner_}@.reserve_hint(); + } }; } \end{codeblock} +\indexlibraryctor{adjacent_transform_view}% \begin{itemdecl} -constexpr explicit adjacent_view(V base); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)}. -\end{itemdescr} - -\begin{itemdecl} -constexpr auto size() requires @\libconcept{sized_range}@; -constexpr auto size() const requires @\libconcept{sized_range}@; +constexpr explicit adjacent_transform_view(V base, F fun); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -using ST = decltype(ranges::size(@\exposid{base_}@)); -using CT = common_type_t; -auto sz = static_cast(ranges::size(@\exposid{base_}@)); -sz -= std::min(sz, N - 1); -return static_cast(sz); -\end{codeblock} +Initializes \exposid{fun_} with \tcode{std::move(fun)} and +\exposid{inner_} with \tcode{std::move(base)}. \end{itemdescr} -\rSec3[range.adjacent.iterator]{Class template \tcode{adjacent_view::\exposid{iterator}}} +\rSec3[range.adjacent.transform.iterator]{Class template \tcode{adjacent_transform_view::\exposid{iterator}}} +\indexlibraryglobal{adjacent_transform_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, size_t N> - requires @\libconcept{view}@ && (N > 0) + template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> + requires @\libconcept{view}@ && (N > 0) && is_object_v && + @\libconcept{regular_invocable}@, N)...> && + @\exposconcept{can-reference}@, N)...>> template - class adjacent_view::@\exposid{iterator}@ { - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - array, N> @\exposid{current_}@ = array, N>(); // \expos - constexpr @\exposidnc{iterator}@(iterator_t<@\exposidnc{Base}@> first, sentinel_t<@\exposidnc{Base}@> last); // \expos - constexpr @\exposidnc{iterator}@(@\exposidnc{as-sentinel}@, iterator_t<@\exposidnc{Base}@> first, iterator_t<@\exposidnc{Base}@> last); - // \expos + class adjacent_transform_view::@\exposid{iterator}@ { + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + @\exposidnc{inner-iterator}@ @\exposid{inner_}@; // \expos + + constexpr @\exposidnc{iterator}@(@\exposidnc{Parent}@& parent, @\exposidnc{inner-iterator}@ inner); // \expos + public: - using iterator_category = input_iterator_tag; - using iterator_concept = @\seebelow@; - using value_type = tuple<@\exposid{REPEAT}@(range_value_t<@\exposid{Base}@>, N)...>; + using iterator_category = @\seebelow@; + using iterator_concept = typename @\exposid{inner-iterator}@::iterator_concept; + using value_type = + remove_cvref_t&, + @\exposid{REPEAT}@(range_reference_t<@\exposid{Base}@>, N)...>>; using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{iterator}@() = default; constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; + requires Const && @\libconcept{convertible_to}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; - constexpr auto operator*() const; + constexpr decltype(auto) operator*() const noexcept(@\seebelow@); constexpr @\exposid{iterator}@& operator++(); constexpr @\exposid{iterator}@ operator++(int); - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - - constexpr auto operator[](difference_type n) const + constexpr decltype(auto) operator[](difference_type n) const requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); @@ -11349,8 +13345,7 @@ friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && - @\libconcept{three_way_comparable}@>; + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@<@\exposid{inner-iterator}@>; friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11359,74 +13354,71 @@ friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; - - friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); - friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) - requires @\libconcept{indirectly_swappable}@>; + requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; }; } \end{codeblock} \pnum -\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +The member \grammarterm{typedef-name} \tcode{\exposid{iterator}::iterator_category} +is defined as follows: \begin{itemize} \item -If \exposid{Base} models \libconcept{random_access_range}, -then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +If \tcode{invoke_result_t<\exposid{maybe-const}\&, +\exposid{REPEAT}(range_reference_t<\exposid{Base}>, N)...>} +is\linebreak not a reference, +\tcode{iterator_category} denotes \tcode{input_iterator_tag}. \item -Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +Otherwise, let \tcode{C} denote the type +\tcode{iterator_traits>::iterator_category}. +\begin{itemize} \item -Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +If \tcode{\libconcept{derived_from}} +is \tcode{true}, +\tcode{iterator_category} denotes \tcode{ran\-dom_access_iterator_tag}. +\item +Otherwise, +if \tcode{\libconcept{derived_from}} +is \tcode{true}, +\tcode{iterator_category} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, +if \tcode{\libconcept{derived_from}} +is \tcode{true}, +\tcode{iterator_category} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\end{itemize} \end{itemize} -\pnum -If the invocation of any non-const member function of \exposid{iterator} -exits via an exception, the \exposid{iterator} acquires a singular value. - -\begin{itemdecl} -constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> first, sentinel_t<@\exposid{Base}@> last); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{\exposid{current_}[0] == first} is \tcode{true}, and -for every integer $1 \leq i < \tcode{N}$, -\tcode{\exposid{current_}[$i$] == ranges::next(\exposid{current_}[$i$-1], 1, last)} -is \tcode{true}. -\end{itemdescr} - +\indexlibraryctor{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{as-sentinel}@, iterator_t<@\exposid{Base}@> first, iterator_t<@\exposid{Base}@> last); +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{inner-iterator}@ inner); \end{itemdecl} \begin{itemdescr} \pnum -\ensures -If \exposid{Base} does not model \libconcept{bidirectional_range}, -each element of \exposid{current_} is equal to \exposid{last}. -Otherwise, \tcode{\exposid{current_}[N-1] == last} is \tcode{true}, and -for every integer $0 \leq i < (\tcode{N} - 1)$, -\tcode{\exposid{current_}[$i$] == ranges::prev(\exposid{current_}[$i$+1], 1, first)} -is \tcode{true}. +\effects +Initializes \exposid{parent_} with \tcode{addressof(parent)} and +\exposid{inner_} with \tcode{std::move(inner)}. \end{itemdescr} +\indexlibraryctor{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; + requires Const && @\libconcept{convertible_to}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes each element of \exposid{current_} -with the corresponding element of \tcode{i.\exposid{current_}} as an xvalue. +Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and +\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. \end{itemdescr} +\indexlibrarymember{operator*}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr auto operator*() const; +constexpr decltype(auto) operator*() const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -11434,31 +13426,23 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); +return apply([&](const auto&... iters) -> decltype(auto) { + return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *iters...); +}, @\exposid{inner_}@.@\exposid{current_}@); \end{codeblock} -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{\exposid{current_}.back()} is incrementable. - -\pnum -\ensures -Each element of \exposid{current_} is equal to \tcode{ranges::next(i)}, -where \tcode{i} is the value of that element before the call. \pnum -\returns -\tcode{*this}. +\remarks +Let \tcode{Is} be the pack \tcode{0, 1, \ldots, (N - 1)}. +The exception specification is equivalent to: +\begin{codeblock} +noexcept(invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *std::get(@\exposid{inner_}@.@\exposid{current_}@)...)) +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} @@ -11466,33 +13450,14 @@ \effects Equivalent to: \begin{codeblock} -auto tmp = *this; -++*this; -return tmp; +++@\exposid{inner_}@; +return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{\exposid{current_}.front()} is decrementable. - -\pnum -\ensures -Each element of \exposid{current_} is equal to \tcode{ranges::prev(i)}, -where \tcode{i} is the value of that element before the call. - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} \begin{itemdescr} @@ -11501,54 +13466,14 @@ Equivalent to: \begin{codeblock} auto tmp = *this; ---*this; +++*this; return tmp; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{\exposid{current_}.back() + x} has well-defined behavior. - -\pnum -\ensures -Each element of \exposid{current_} is equal to \tcode{i + x}, -where \tcode{i} is the value of that element before the call. - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{\exposid{current_}.front() - x} has well-defined behavior. - -\pnum -\ensures -Each element of \exposid{current_} is equal to \tcode{i - x}, -where \tcode{i} is the value of that element before the call. - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\begin{itemdecl} -constexpr auto operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -11556,80 +13481,60 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{tuple-transform}@([&](auto& i) -> decltype(auto) { return i[n]; }, @\exposid{current_}@); +--@\exposid{inner_}@; +return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x.\exposid{current_}.back() == y.\exposid{current_}.back()}. -\end{itemdescr} - -\begin{itemdecl} -friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x.\exposid{current_}.back() < y.\exposid{current_}.back()}. -\end{itemdescr} - -\begin{itemdecl} -friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return y < x;} -\end{itemdescr} - -\begin{itemdecl} -friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(y < x);} +Equivalent to: +\begin{codeblock} +auto tmp = *this; +--*this; +return tmp; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(x < y);} +Equivalent to: +\begin{codeblock} +@\exposid{inner_}@ += x; +return *this; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-=}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && - @\libconcept{three_way_comparable}@>; +constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_}.back() <=> y.\exposid{current_}.back()}. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{inner_}@ -= x; +return *this; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator[]}{adjacent_transform_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) +constexpr decltype(auto) operator[](difference_type n) const requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} @@ -11638,449 +13543,413 @@ \effects Equivalent to: \begin{codeblock} -auto r = i; -r += n; -return r; +return apply([&](const auto&... iters) -> decltype(auto) { + return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, iters[n]...); +}, @\exposid{inner_}@.@\exposid{current_}@); \end{codeblock} \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@<@\exposid{inner-iterator}@>; \end{itemdecl} \begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. + \pnum \effects -Equivalent to: -\begin{codeblock} -auto r = i; -r -= n; -return r; -\end{codeblock} +Equivalent to: \tcode{return x.\exposid{inner_} \placeholder{op} y.\exposid{inner_};} \end{itemdescr} \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return x.\exposid{current_}.back() - y.\exposid{current_}.back();} +Equivalent to: \tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} + n);} \end{itemdescr} \begin{itemdecl} -friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return \exposid{tuple-transform}(ranges::iter_move, i.\exposid{current_});} - -\pnum -\remarks -The exception specification is equivalent to: -\begin{codeblock} -noexcept(ranges::iter_move(declval&>())) && -is_nothrow_move_constructible_v> -\end{codeblock} +Equivalent to: \tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} - n);} \end{itemdescr} \begin{itemdecl} -friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) - requires @\libconcept{indirectly_swappable}@>; +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -None of the iterators in \tcode{l.\exposid{current_}} is equal to -an iterator in \tcode{r.\exposid{current_}}. - \pnum \effects -For every integer $0 \leq i < \tcode{N}$, -performs -\tcode{ranges::iter_swap(l.\exposid{current_}[$i$], r.\exposid{current_}[$i$])}. - -\pnum -\remarks -The exception specification is equivalent to: -\begin{codeblock} -noexcept(ranges::iter_swap(declval>(), declval>())) -\end{codeblock} +Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} \end{itemdescr} -\rSec3[range.adjacent.sentinel]{Class template \tcode{adjacent_view::\exposid{sentinel}}} +\rSec3[range.adjacent.transform.sentinel]{Class template \tcode{adjacent_transform_view::\exposid{sentinel}}} +\indexlibraryglobal{adjacent_transform_view::\exposid{sentinel}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, size_t N> - requires @\libconcept{view}@ && (N > 0) + template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> + requires @\libconcept{view}@ && (N > 0) && is_object_v && + @\libconcept{regular_invocable}@, N)...> && + @\exposconcept{can-reference}@, N)...>> template - class adjacent_view::@\exposid{sentinel}@ { - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos - sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos - constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); // \expos + class adjacent_transform_view::@\exposid{sentinel}@ { + @\exposidnc{inner-sentinel}@ @\exposid{inner_}@; // \expos + constexpr explicit @\exposidnc{sentinel}@(@\exposidnc{inner-sentinel}@ inner); // \expos public: @\exposid{sentinel}@() = default; constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + requires Const && @\libconcept{convertible_to}@<@\exposid{inner-sentinel}@, @\exposid{inner-sentinel}@>; template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + requires @\libconcept{sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr range_difference_t<@\exposid{maybe-const}@> + requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> + friend constexpr range_difference_t<@\exposid{maybe-const}@> operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); + requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> + friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); }; } \end{codeblock} +\indexlibraryctor{adjacent_transform_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); +constexpr explicit @\exposid{sentinel}@(@\exposid{inner-sentinel}@ inner); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end}. +Initializes \exposid{inner_} with \tcode{inner}. \end{itemdescr} +\indexlibraryctor{adjacent_transform_view::\exposid{sentinel}}% \begin{itemdecl} constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + requires Const && @\libconcept{convertible_to}@<@\exposid{inner-sentinel}@, @\exposid{inner-sentinel}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. +Initializes \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. \end{itemdescr} \begin{itemdecl} template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + requires @\libconcept{sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_}.back() == y.\exposid{end_};} +Equivalent to: \tcode{return x.\exposid{inner_} == y.\exposid{inner_};} +\end{itemdescr} + +\begin{itemdecl} +template + requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + +template + requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> +friend constexpr range_difference_t<@\exposid{maybe-const}@> + operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +\end{itemdescr} + +\rSec2[range.chunk]{Chunk view} + +\rSec3[range.chunk.overview]{Overview} + +\pnum +\tcode{chunk_view} takes a view and a number $N$ and +produces a range of views +that are $N$-sized non-overlapping successive chunks of +the elements of the original view, in order. +The last view in the range can have fewer than $N$ elements. + +\pnum +\indexlibrarymember{chunk}{views}% +The name \tcode{views::chunk} denotes +a range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{N}, +the expression \tcode{views::chunk(E, N)} is expression-equivalent to +\tcode{chunk_view(E, N)}. + +\begin{example} +\begin{codeblock} +vector v = {1, 2, 3, 4, 5}; + +for (auto r : v | views::chunk(2)) { + cout << '['; + auto sep = ""; + for (auto i : r) { + cout << sep << i; + sep = ", "; + } + cout << "] "; +} +// The above prints \tcode{[1, 2] [3, 4] [5]} +\end{codeblock} +\end{example} + +\rSec3[range.chunk.view.input]{Class template \tcode{chunk_view} for input ranges} + +\indexlibraryglobal{chunk_view}% +\begin{codeblock} +namespace std::ranges { + template + constexpr I @\exposidnc{div-ceil}@(I num, I denom) { // \expos + I r = num / denom; + if (num % denom) + ++r; + return r; + } + + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + class chunk_view : public view_interface> { + V @\exposid{base_}@; // \expos + range_difference_t @\exposid{n_}@; // \expos + range_difference_t @\exposid{remainder_}@ = 0; // \expos + + @\exposid{non-propagating-cache}@> @\exposid{current_}@; // \expos + + // \ref{range.chunk.outer.iter}, class \tcode{chunk_view::\exposid{outer-iterator}} + class @\exposid{outer-iterator}@; // \expos + + // \ref{range.chunk.inner.iter}, class \tcode{chunk_view::\exposid{inner-iterator}} + class @\exposid{inner-iterator}@; // \expos + + public: + constexpr explicit chunk_view(V base, range_difference_t n); + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + + constexpr @\exposid{outer-iterator}@ begin(); + constexpr default_sentinel_t end() const noexcept; + + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; + }; + + template + chunk_view(R&&, range_difference_t) -> chunk_view>; +} +\end{codeblock} + +\indexlibraryctor{chunk_view}% +\begin{itemdecl} +constexpr explicit chunk_view(V base, range_difference_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{n > 0} is \tcode{true}. + +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{n_} with \tcode{n}. \end{itemdescr} +\indexlibrarymember{begin}{chunk_view}% \begin{itemdecl} -template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +constexpr @\exposid{outer-iterator}@ begin(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_}.back() - y.\exposid{end_};} +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ = ranges::begin(@\exposid{base_}@); +@\exposid{remainder_}@ = @\exposid{n_}@; +return @\exposid{outer-iterator}@(*this); +\end{codeblock} \end{itemdescr} +\indexlibrarymember{end}{chunk_view}% \begin{itemdecl} -template - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); +constexpr default_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return y.\exposid{end_} - x.\exposid{current_}.back();} +\returns +\tcode{default_sentinel}. \end{itemdescr} -\rSec2[range.adjacent.transform]{Adjacent transform view} - -\rSec3[range.adjacent.transform.overview]{Overview} - -\pnum -\indexlibraryglobal{adjacent_transform_view}% -\tcode{adjacent_transform_view} takes an invocable object and -a view and produces a view -whose $M^\text{th}$ element is the result of applying the invocable object -to the $M^\text{th}$ through $(M + N - 1)^\text{th}$ elements -of the original view. -If the original view has fewer than $N$ elements, the resulting view is empty. - -\pnum -\indexlibrarymember{adjacent_transform}{views}% -The name \tcode{views::adjacent_transform} denotes -a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{F} and -a constant expression \tcode{N}: -\begin{itemize} -\item -If \tcode{N} is equal to \tcode{0}, -\tcode{views::adjacent_transform(E, F)} is expression-equivalent to -\tcode{((void)E, views::zip_transform(F))}, -except that the evaluations of \tcode{E} and \tcode{F} are -indeterminately sequenced. -\item -Otherwise, -the expression \tcode{views::adjacent_transform(E, F)} is -expression-equivalent to -\tcode{adja\-cent_transform_view, decay_t, N>(E, F)}. -\end{itemize} +\indexlibrarymember{size}{chunk_view}% +\begin{itemdecl} +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{example} -\begin{codeblock} -vector v = {1, 2, 3, 4}; - -for (auto i : v | views::adjacent_transform<2>(std::multiplies())) { - cout << i << ' '; // prints \tcode{2 6 12} -} -\end{codeblock} -\end{example} - -\rSec3[range.adjacent.transform.view]{Class template \tcode{adjacent_transform_view}} - -\indexlibrarymember{begin}{adjacent_transform_view}% -\indexlibrarymember{end}{adjacent_transform_view}% -\indexlibrarymember{size}{adjacent_transform_view}% +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> - requires @\libconcept{view}@ && (N > 0) && is_object_v && - @\libconcept{regular_invocable}@, N)...> && - @\exposconcept{can-reference}@, N)...>> - class adjacent_transform_view : public view_interface> { - @\exposidnc{movable-box}@ @\exposid{fun_}@; // \expos - adjacent_view @\exposid{inner_}@; // \expos - - using @\exposidnc{InnerView}@ = adjacent_view; // \expos - template - using @\exposid{inner-iterator}@ = iterator_t<@\exposid{maybe-const}@>; // \expos - template - using @\exposid{inner-sentinel}@ = sentinel_t<@\exposid{maybe-const}@>; // \expos - - // \ref{range.adjacent.transform.iterator}, class template \tcode{adjacent_transform_view::\exposid{iterator}} - template class @\exposidnc{iterator}@; // \expos - - // \ref{range.adjacent.transform.sentinel}, class template \tcode{adjacent_transform_view::\exposid{sentinel}} - template class @\exposidnc{sentinel}@; // \expos - - public: - adjacent_transform_view() = default; - constexpr explicit adjacent_transform_view(V base, F fun); - - constexpr V base() const & requires @\libconcept{copy_constructible}@<@\exposid{InnerView}@> { return @\exposid{inner_}@.base(); } - constexpr V base() && { return std::move(@\exposid{inner_}@).base(); } - - constexpr auto begin() { - return @\exposid{iterator}@(*this, @\exposid{inner_}@.begin()); - } - - constexpr auto begin() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@, N)...> { - return @\exposid{iterator}@(*this, @\exposid{inner_}@.begin()); - } - - constexpr auto end() { - if constexpr (@\libconcept{common_range}@<@\exposid{InnerView}@>) { - return @\exposid{iterator}@(*this, @\exposid{inner_}@.end()); - } else { - return @\exposid{sentinel}@(@\exposid{inner_}@.end()); - } - } - - constexpr auto end() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@, N)...> { - if constexpr (@\libconcept{common_range}@) { - return @\exposid{iterator}@(*this, @\exposid{inner_}@.end()); - } else { - return @\exposid{sentinel}@(@\exposid{inner_}@.end()); - } - } - - constexpr auto size() requires @\libconcept{sized_range}@<@\exposid{InnerView}@> { - return @\exposid{inner_}@.size(); - } - - constexpr auto size() const requires @\libconcept{sized_range}@ { - return @\exposid{inner_}@.size(); - } - }; -} +return @\exposid{to-unsigned-like}@(@\exposidnc{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); \end{codeblock} +\end{itemdescr} +\indexlibrarymember{reserve_hint}{chunk_view}% \begin{itemdecl} -constexpr explicit adjacent_transform_view(V base, F fun); +constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; +constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{fun_} with \tcode{std::move(fun)} and -\exposid{inner_} with \tcode{std::move(base)}. +Equivalent to: +\begin{codeblock} +auto s = static_cast>(ranges::reserve_hint(@\exposidnc{base_}@)); +return @\exposidnc{to-unsigned-like}@(@\exposidnc{div-ceil}@(s, @\exposidnc{n_}@)); +\end{codeblock} \end{itemdescr} -\rSec3[range.adjacent.transform.iterator]{Class template \tcode{adjacent_transform_view::\exposid{iterator}}} +\rSec3[range.chunk.outer.iter]{Class \tcode{chunk_view::\exposid{outer-iterator}}} +\indexlibraryglobal{chunk_view::\exposid{outer-iterator}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> - requires @\libconcept{view}@ && (N > 0) && is_object_v && - @\libconcept{regular_invocable}@, N)...> && - @\exposconcept{can-reference}@, N)...>> - template - class adjacent_transform_view::@\exposid{iterator}@ { - using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos - @\exposidnc{inner-iterator}@ @\exposid{inner_}@; // \expos + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + class chunk_view::@\exposid{outer-iterator}@ { + chunk_view* @\exposid{parent_}@; // \expos - constexpr @\exposidnc{iterator}@(@\exposidnc{Parent}@& parent, @\exposidnc{inner-iterator}@ inner); // \expos + constexpr explicit @\exposid{outer-iterator}@(chunk_view& parent); // \expos public: - using iterator_category = @\seebelow@; - using iterator_concept = typename @\exposid{inner-iterator}@::iterator_concept; - using value_type = - remove_cvref_t&, - @\exposid{REPEAT}@(range_reference_t<@\exposid{Base}@>, N)...>>; - using difference_type = range_difference_t<@\exposid{Base}@>; - - @\exposid{iterator}@() = default; - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; + using iterator_concept = input_iterator_tag; + using difference_type = range_difference_t; - constexpr decltype(auto) operator*() const noexcept(@\seebelow@); - constexpr @\exposid{iterator}@& operator++(); - constexpr @\exposid{iterator}@ operator++(int); - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + // \ref{range.chunk.outer.value}, class \tcode{chunk_view::\exposid{outer-iterator}::value_type} + struct value_type; - constexpr decltype(auto) operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + @\exposid{outer-iterator}@(@\exposid{outer-iterator}@&&) = default; + @\exposid{outer-iterator}@& operator=(@\exposid{outer-iterator}@&&) = default; - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); - friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@<@\exposid{inner-iterator}@>; + constexpr value_type operator*() const; + constexpr @\exposid{outer-iterator}@& operator++(); + constexpr void operator++(int); - friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; - }; -} -\end{codeblock} + friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); -\pnum -The member \grammarterm{typedef-name} \tcode{\exposid{iterator}::iterator_category} -is defined as follows: -\begin{itemize} -\item -If \tcode{invoke_result_t<\exposid{maybe-const}\&, -\exposid{REPEAT}(range_reference_t<\exposid{Base}>, N)...>} -is\linebreak not a reference, -\tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\item -Otherwise, let \tcode{C} denote the type -\tcode{iterator_traits>::iterator_category}. -\begin{itemize} -\item -If \tcode{\libconcept{derived_from}} -is \tcode{true}, -\tcode{iterator_category} denotes \tcode{ran\-dom_access_iterator_tag}. -\item -Otherwise, -if \tcode{\libconcept{derived_from}} -is \tcode{true}, -\tcode{iterator_category} denotes \tcode{bidirectional_iterator_tag}. -\item -Otherwise, -if \tcode{\libconcept{derived_from}} -is \tcode{true}, -\tcode{iterator_category} denotes \tcode{forward_iterator_tag}. -\item -Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\end{itemize} -\end{itemize} + friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{outer-iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + friend constexpr difference_type operator-(const @\exposid{outer-iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + }; +} +\end{codeblock} +\indexlibraryctor{chunk_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{inner-iterator}@ inner); +constexpr explicit @\exposid{outer-iterator}@(chunk_view& parent); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)} and -\exposid{inner_} with \tcode{std::move(inner)}. +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} +\indexlibrarymember{operator*}{chunk_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; +constexpr value_type operator*() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and -\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. +\expects +\tcode{*this == default_sentinel} is \tcode{false}. + +\pnum +\returns +\tcode{value_type(*\exposid{parent_})}. \end{itemdescr} +\indexlibrarymember{operator++}{chunk_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr decltype(auto) operator*() const noexcept(@\seebelow@); +constexpr @\exposid{outer-iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{*this == default_sentinel} is \tcode{false}. + \pnum \effects Equivalent to: \begin{codeblock} -return apply([&](const auto&... iters) -> decltype(auto) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *iters...); -}, @\exposid{inner_}@.@\exposid{current_}@); +ranges::advance(*@\exposid{parent_}@->@\exposid{current_}@, @\exposid{parent_}@->@\exposid{remainder_}@, ranges::end(@\exposid{parent_}@->@\exposid{base_}@)); +@\exposid{parent_}@->@\exposid{remainder_}@ = @\exposid{parent_}@->@\exposid{n_}@; +return *this; \end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{chunk_view::\exposid{outer-iterator}}% +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} +\begin{itemdescr} \pnum -\remarks -Let \tcode{Is} be the pack \tcode{0, 1, \ldots, (N-1)}. -The exception specification is equivalent to: -\begin{codeblock} -noexcept(invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *std::get(@\exposid{inner_}@.@\exposid{current_}@)...)) -\end{codeblock} +\effects +Equivalent to \tcode{++*this}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} @@ -12088,13 +13957,13 @@ \effects Equivalent to: \begin{codeblock} -++@\exposid{inner_}@; -return *this; +return *x.@\exposid{parent_}@->@\exposid{current_}@ == ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) && x.@\exposid{parent_}@->@\exposid{remainder_}@ != 0; \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{outer-iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} @@ -12102,28 +13971,85 @@ \effects Equivalent to: \begin{codeblock} -auto tmp = *this; -++*this; -return tmp; +const auto dist = ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) - *x.@\exposid{parent_}@->@\exposid{current_}@; +if (dist < x.@\exposid{parent_}@->@\exposid{remainder_}@) { + return dist == 0 ? 0 : 1; +} +return @\exposidnc{div-ceil}@(dist - x.@\exposid{parent_}@->@\exposid{remainder_}@, x.@\exposid{parent_}@->@\exposid{n_}@) + 1; \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +friend constexpr difference_type operator-(const @\exposid{outer-iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: +Equivalent to: \tcode{return -(y - x);} +\end{itemdescr} + +\rSec3[range.chunk.outer.value]{Class \tcode{chunk_view::\exposid{outer-iterator}::value_type}} + +\indexlibraryglobal{chunk_view::\exposid{outer-iterator}::value_type}% \begin{codeblock} ---@\exposid{inner_}@; -return *this; +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + struct chunk_view::@\exposid{outer-iterator}@::value_type : view_interface { + private: + chunk_view* @\exposid{parent_}@; // \expos + + constexpr explicit value_type(chunk_view& parent); // \expos + + public: + constexpr @\exposid{inner-iterator}@ begin() const noexcept; + constexpr default_sentinel_t end() const noexcept; + + constexpr auto size() const + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + }; +} \end{codeblock} + +\indexlibraryctor{chunk_view::\exposid{outer-iterator}::value_type}% +\begin{itemdecl} +constexpr explicit value_type(chunk_view& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} +\indexlibrarymember{begin}{chunk_view::\exposid{outer-iterator}::value_type}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{inner-iterator}@ begin() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{inner-iterator}(*\exposid{parent_})}. +\end{itemdescr} + +\indexlibrarymember{end}{chunk_view::\exposid{outer-iterator}::value_type}% +\begin{itemdecl} +constexpr default_sentinel_t end() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{default_sentinel}. +\end{itemdescr} + +\indexlibrarymember{size}{chunk_view::\exposid{outer-iterator}::value_type}% +\begin{itemdecl} +constexpr auto size() const + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} @@ -12131,384 +14057,433 @@ \effects Equivalent to: \begin{codeblock} -auto tmp = *this; ---*this; -return tmp; +return @\exposid{to-unsigned-like}@(ranges::min(@\exposid{parent_}@->@\exposid{remainder_}@, + ranges::end(@\exposid{parent_}@->@\exposid{base_}@) - *@\exposid{parent_}@->@\exposid{current_}@)); +\end{codeblock} +\end{itemdescr} + +\rSec3[range.chunk.inner.iter]{Class \tcode{chunk_view::\exposid{inner-iterator}}} + +\indexlibraryglobal{chunk_view::\exposid{inner-iterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + class chunk_view::@\exposid{inner-iterator}@ { + chunk_view* @\exposid{parent_}@; // \expos + + constexpr explicit @\exposid{inner-iterator}@(chunk_view& parent) noexcept; // \expos + + public: + using iterator_concept = input_iterator_tag; + using difference_type = range_difference_t; + using value_type = range_value_t; + + @\exposid{inner-iterator}@(@\exposid{inner-iterator}@&&) = default; + @\exposid{inner-iterator}@& operator=(@\exposid{inner-iterator}@&&) = default; + + constexpr const iterator_t& base() const &; + + constexpr range_reference_t operator*() const; + constexpr @\exposid{inner-iterator}@& operator++(); + constexpr void operator++(int); + + friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); + + friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{inner-iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + friend constexpr difference_type operator-(const @\exposid{inner-iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + + friend constexpr range_rvalue_reference_t iter_move(const @\exposid{inner-iterator}@& i) + noexcept(noexcept(ranges::iter_move(*i.@\exposid{parent_}@->@\exposid{current_}@))); + + friend constexpr void iter_swap(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) + noexcept(noexcept(ranges::iter_swap(*x.@\exposid{parent_}@->@\exposid{current_}@, *y.@\exposid{parent_}@->@\exposid{current_}@))) + requires @\libconcept{indirectly_swappable}@>; + }; +} \end{codeblock} + +\indexlibraryctor{chunk_view::\exposid{inner-iterator}}% +\begin{itemdecl} +constexpr explicit @\exposid{inner-iterator}@(chunk_view& parent) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} +\indexlibrarymember{base}{chunk_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr const iterator_t& base() const &; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -@\exposid{inner_}@ += x; -return *this; -\end{codeblock} +Equivalent to: \tcode{return *\exposid{parent_}->\exposid{current_};} \end{itemdescr} +\indexlibrarymember{operator*}{chunk_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr range_reference_t operator*() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{*this == default_sentinel} is \tcode{false}. + +\pnum +\effects +Equivalent to: \tcode{return **\exposid{parent_}->\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator++}{chunk_view::\exposid{inner-iterator}}% +\begin{itemdecl} +constexpr @\exposid{inner-iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{*this == default_sentinel} is \tcode{false}. + \pnum \effects Equivalent to: \begin{codeblock} -@\exposid{inner_}@ -= x; +++*@\exposid{parent_}@->@\exposid{current_}@; +if (*@\exposid{parent_}@->@\exposid{current_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) + @\exposid{parent_}@->@\exposid{remainder_}@ = 0; +else + --@\exposid{parent_}@->@\exposid{remainder_}@; return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{chunk_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr decltype(auto) operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return apply([&](const auto&... iters) -> decltype(auto) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, iters[n]...); -}, @\exposid{inner_}@.@\exposid{current_}@); -\end{codeblock} +Equivalent to \tcode{++*this}. \end{itemdescr} +\indexlibrarymember{operator==}{chunk_view::\exposid{inner-iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); -friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@<@\exposid{inner-iterator}@>; +friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum -Let \placeholder{op} be the operator. +\returns +\tcode{x.\exposid{parent_}->\exposid{remainder_} == 0}. +\end{itemdescr} + +\indexlibrarymember{operator-}{chunk_view::\exposid{inner-iterator}}% +\begin{itemdecl} +friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{inner-iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; +\end{itemdecl} +\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{inner_} \placeholder{op} y.\exposid{inner_};} +Equivalent to: +\begin{codeblock} +return ranges::min(x.@\exposid{parent_}@->@\exposid{remainder_}@, + ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) - *x.@\exposid{parent_}@->@\exposid{current_}@); +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-}{chunk_view::\exposid{inner-iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr difference_type operator-(const @\exposid{inner-iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} + n);} +Equivalent to: \tcode{return -(y - x);} \end{itemdescr} +\indexlibrarymember{iter_move}{chunk_view::\exposid{inner-iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr range_rvalue_reference_t iter_move(const @\exposid{inner-iterator}@& i) + noexcept(noexcept(ranges::iter_move(*i.@\exposid{parent_}@->@\exposid{current_}@))); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} - n);} +Equivalent to: \tcode{return ranges::iter_move(*i.\exposid{parent_}->\exposid{current_});} \end{itemdescr} +\indexlibrarymember{iter_swap}{chunk_view::\exposid{inner-iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; +friend constexpr void iter_swap(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) + noexcept(noexcept(ranges::iter_swap(*x.@\exposid{parent_}@->@\exposid{current_}@, *y.@\exposid{parent_}@->@\exposid{current_}@))) + requires @\libconcept{indirectly_swappable}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +Equivalent to: \tcode{ranges::iter_swap(*x.\exposid{parent_}->\exposid{current_}, *y.\exposid{parent_}->\exposid{current_});} \end{itemdescr} -\rSec3[range.adjacent.transform.sentinel]{Class template \tcode{adjacent_transform_view::\exposid{sentinel}}} +\rSec3[range.chunk.view.fwd]{Class template \tcode{chunk_view} for forward ranges} +\indexlibraryglobal{chunk_view}% +\indexlibrarymember{begin}{chunk_view}% +\indexlibrarymember{end}{chunk_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> - requires @\libconcept{view}@ && (N > 0) && is_object_v && - @\libconcept{regular_invocable}@, N)...> && - @\exposconcept{can-reference}@, N)...>> - template - class adjacent_transform_view::@\exposid{sentinel}@ { - @\exposidnc{inner-sentinel}@ @\exposid{inner_}@; // \expos - constexpr explicit @\exposidnc{sentinel}@(@\exposidnc{inner-sentinel}@ inner); // \expos + template<@\libconcept{view}@ V> + requires @\libconcept{forward_range}@ + class chunk_view : public view_interface> { + V @\exposid{base_}@; // \expos + range_difference_t @\exposid{n_}@; // \expos + + // \ref{range.chunk.fwd.iter}, class template \tcode{chunk_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos public: - @\exposid{sentinel}@() = default; - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{inner-sentinel}@, @\exposid{inner-sentinel}@>; + constexpr explicit chunk_view(V base, range_difference_t n); - template - requires @\libconcept{sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } - template - requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> - friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + constexpr auto begin() requires (!@\exposconcept{simple-view}@) { + return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); + } - template - requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> - friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); + constexpr auto begin() const requires @\libconcept{forward_range}@ { + return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); + } + + constexpr auto end() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@) { + auto missing = (@\exposid{n_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{n_}@) % @\exposid{n_}@; + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); + } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); + } else { + return default_sentinel; + } + } + + constexpr auto end() const requires @\libconcept{forward_range}@ { + if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@) { + auto missing = (@\exposid{n_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{n_}@) % @\exposid{n_}@; + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); + } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); + } else { + return default_sentinel; + } + } + + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; + + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; }; } \end{codeblock} +\indexlibraryctor{chunk_view}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(@\exposid{inner-sentinel}@ inner); +constexpr explicit chunk_view(V base, range_difference_t n); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{inner_} with \tcode{inner}. -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{inner-sentinel}@, @\exposid{inner-sentinel}@>; -\end{itemdecl} +\expects +\tcode{n > 0} is \tcode{true}. -\begin{itemdescr} \pnum \effects -Initializes \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{n_} with \tcode{n}. \end{itemdescr} +\indexlibrarymember{size}{chunk_view}% \begin{itemdecl} -template - requires @\libconcept{sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{inner_} == y.\exposid{inner_};} +Equivalent to: +\begin{codeblock} +return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); +\end{codeblock} \end{itemdescr} +\indexlibrarymember{reserve_hint}{chunk_view}% \begin{itemdecl} -template - requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); - -template - requires @\libconcept{sized_sentinel_for}@<@\exposid{inner-sentinel}@, @\exposid{inner-iterator}@> -friend constexpr range_difference_t<@\exposid{maybe-const}@> - operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y); +constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; +constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} -\end{itemdescr} - -\rSec2[range.chunk]{Chunk view} - -\rSec3[range.chunk.overview]{Overview} - -\pnum -\tcode{chunk_view} takes a view and a number $N$ and -produces a range of views -that are $N$-sized non-overlapping successive chunks of -the elements of the original view, in order. -The last view in the range can have fewer than $N$ elements. - -\pnum -\indexlibrarymember{chunk}{views}% -The name \tcode{views::chunk} denotes -a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{N}, -the expression \tcode{views::chunk(E, N)} is expression-equivalent to -\tcode{chunk_view(E, N)}. - -\begin{example} +Equivalent to: \begin{codeblock} -vector v = {1, 2, 3, 4, 5}; - -for (auto r : v | views::chunk(2)) { - cout << '['; - auto sep = ""; - for (auto i : r) { - cout << sep << i; - sep = ", "; - } - cout << "] "; -} -// The above prints \tcode{[1, 2] [3, 4] [5]} +auto s = static_cast>(ranges::reserve_hint(@\exposid{base_}@)); +return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(s, @\exposid{n_}@)); \end{codeblock} -\end{example} +\end{itemdescr} -\rSec3[range.chunk.view.input]{Class template \tcode{chunk_view} for input ranges} +\rSec3[range.chunk.fwd.iter]{Class template \tcode{chunk_view::\exposid{iterator}} for forward ranges} -\indexlibrarymember{begin}{chunk_view}% -\indexlibrarymember{end}{chunk_view}% -\indexlibrarymember{size}{chunk_view}% +\indexlibraryglobal{chunk_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { - template - constexpr I @\exposidnc{div-ceil}@(I num, I denom) { // \expos - I r = num / denom; - if (num % denom) - ++r; - return r; - } - template<@\libconcept{view}@ V> - requires @\libconcept{input_range}@ - class chunk_view : public view_interface> { - V @\exposid{base_}@; // \expos - range_difference_t @\exposid{n_}@; // \expos - range_difference_t @\exposid{remainder_}@ = 0; // \expos - - @\exposid{non-propagating-cache}@> @\exposid{current_}@; // \expos + requires @\libconcept{forward_range}@ + template + class chunk_view::@\exposid{iterator}@ { + using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos - // \ref{range.chunk.outer.iter}, class \tcode{chunk_view::\exposid{outer-iterator}} - class @\exposid{outer-iterator}@; // \expos + iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos + sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + range_difference_t<@\exposid{Base}@> @\exposid{n_}@ = 0; // \expos + range_difference_t<@\exposid{Base}@> @\exposid{missing_}@ = 0; // \expos - // \ref{range.chunk.inner.iter}, class \tcode{chunk_view::\exposid{inner-iterator}} - class @\exposid{inner-iterator}@; // \expos + constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, // \expos + range_difference_t<@\exposid{Base}@> missing = 0); public: - constexpr explicit chunk_view(V base, range_difference_t n); + using iterator_category = input_iterator_tag; + using iterator_concept = @\seebelow@; + using value_type = decltype(views::take(subrange(@\exposid{current_}@, @\exposid{end_}@), @\exposid{n_}@)); + using difference_type = range_difference_t<@\exposid{Base}@>; - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + @\exposid{iterator}@() = default; + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> + && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; - constexpr @\exposid{outer-iterator}@ begin(); - constexpr default_sentinel_t end() const noexcept; + constexpr iterator_t<@\exposid{Base}@> base() const; - constexpr auto size() requires @\libconcept{sized_range}@; - constexpr auto size() const requires @\libconcept{sized_range}@; - }; + constexpr value_type operator*() const; + constexpr @\exposid{iterator}@& operator++(); + constexpr @\exposid{iterator}@ operator++(int); - template - chunk_view(R&&, range_difference_t) -> chunk_view>; -} -\end{codeblock} + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; -\begin{itemdecl} -constexpr explicit chunk_view(V base, range_difference_t n); -\end{itemdecl} + constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\begin{itemdescr} -\pnum -\expects -\tcode{n > 0} is \tcode{true}. + constexpr value_type operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{n_} with \tcode{n}. -\end{itemdescr} + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); + friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); + + friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && + @\libconcept{three_way_comparable}@>; + + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; -\begin{itemdecl} -constexpr @\exposid{outer-iterator}@ begin(); -\end{itemdecl} + friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + }; +} +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{current_}@ = ranges::begin(@\exposid{base_}@); -@\exposid{remainder_}@ = @\exposid{n_}@; -return @\exposid{outer-iterator}@(*this); -\end{codeblock} -\end{itemdescr} +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +\begin{itemize} +\item +If \exposid{Base} models \libconcept{random_access_range}, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +\end{itemize} +\indexlibraryctor{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr default_sentinel_t end() const noexcept; +constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, + range_difference_t<@\exposid{Base}@> missing = 0); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{default_sentinel}. +\effects +Initializes \exposid{current_} with \tcode{current}, +\exposid{end_} with \tcode{ranges::end(parent->\exposid{base_})}, +\exposid{n_} with \tcode{parent\linebreak ->\exposid{n_}}, and +\exposid{missing_} with \tcode{missing}. \end{itemdescr} +\indexlibraryctor{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr auto size() requires @\libconcept{sized_range}@; -constexpr auto size() const requires @\libconcept{sized_range}@; +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> + && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return @\exposid{to-unsigned-like}@(@\exposidnc{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); -\end{codeblock} +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}, +\exposid{end_} with \tcode{std::move(i.\exposid{end_})}, +\exposid{n_} with \tcode{i.\exposid{n_}}, and +\exposid{missing_} with \tcode{i.\exposid{missing_}}. \end{itemdescr} -\rSec3[range.chunk.outer.iter]{Class \tcode{chunk_view::\exposid{outer-iterator}}} - -\indexlibraryglobal{chunk_view::outer-iterator}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{input_range}@ - class chunk_view::@\exposid{outer-iterator}@ { - chunk_view* @\exposid{parent_}@; // \expos - - constexpr explicit @\exposid{outer-iterator}@(chunk_view& parent); // \expos - - public: - using iterator_concept = input_iterator_tag; - using difference_type = range_difference_t; - - // \ref{range.chunk.outer.value}, class \tcode{chunk_view::\exposid{outer-iterator}::value_type} - struct value_type; - - @\exposid{outer-iterator}@(@\exposid{outer-iterator}@&&) = default; - @\exposid{outer-iterator}@& operator=(@\exposid{outer-iterator}@&&) = default; - - constexpr value_type operator*() const; - constexpr @\exposid{outer-iterator}@& operator++(); - constexpr void operator++(int); - - friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); - - friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{outer-iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; - friend constexpr difference_type operator-(const @\exposid{outer-iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; - }; -} -\end{codeblock} - +\indexlibrarymember{base}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{outer-iterator}@(chunk_view& parent); +constexpr iterator_t<@\exposid{Base}@> base() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}. +\returns +\exposid{current_}. \end{itemdescr} +\indexlibrarymember{operator*}{chunk_view::\exposid{iterator}}% \begin{itemdecl} constexpr value_type operator*() const; \end{itemdecl} @@ -12516,44 +14491,51 @@ \begin{itemdescr} \pnum \expects -\tcode{*this == default_sentinel} is \tcode{false}. +\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. \pnum \returns -\tcode{value_type(*\exposid{parent_})}. +\tcode{views::take(subrange(\exposid{current_}, \exposid{end_}), \exposid{n_})}. \end{itemdescr} +\indexlibrarymember{operator++}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{outer-iterator}@& operator++(); +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{*this == default_sentinel} is \tcode{false}. +\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. \pnum \effects Equivalent to: \begin{codeblock} -ranges::advance(*@\exposid{parent_}@->@\exposid{current_}@, @\exposid{parent_}@->@\exposid{remainder_}@, ranges::end(@\exposid{parent_}@->@\exposid{base_}@)); -@\exposid{parent_}@->@\exposid{remainder_}@ = @\exposid{parent_}@->@\exposid{n_}@; +@\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@, @\exposid{end_}@); return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr void operator++(int); +constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{++*this}. +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -12561,13 +14543,15 @@ \effects Equivalent to: \begin{codeblock} -return *x.@\exposid{parent_}@->@\exposid{current_}@ == ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) && x.@\exposid{parent_}@->@\exposid{remainder_}@ != 0; +ranges::advance(@\exposid{current_}@, @\exposid{missing_}@ - @\exposid{n_}@); +@\exposid{missing_}@ = 0; +return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{outer-iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -12575,215 +14559,156 @@ \effects Equivalent to: \begin{codeblock} -const auto dist = ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) - *x.@\exposid{parent_}@->@\exposid{current_}@; -if (dist < x.@\exposid{parent_}@->@\exposid{remainder_}@) { - return dist == 0 ? 0 : 1; -} -return @\exposidnc{div-ceil}@(dist - x.@\exposid{parent_}@->@\exposid{remainder_}@, x.@\exposid{parent_}@->@\exposid{n_}@) + 1; +auto tmp = *this; +--*this; +return tmp; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{outer-iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return -(y - x);} -\end{itemdescr} - -\rSec3[range.chunk.outer.value]{Class \tcode{chunk_view::\exposid{outer-iterator}::value_type}} +\expects +If \tcode{x} is positive, +\tcode{ranges::distance(\exposid{current_}, \exposid{end_}) > \exposid{n_} * (x - 1)} +is \tcode{true}. +\begin{note} +If \tcode{x} is negative, the \Fundescx{Effects} paragraph implies a precondition. +\end{note} -\indexlibraryglobal{chunk_view::outer-iterator::value_type}% +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{input_range}@ - struct chunk_view::@\exposid{outer-iterator}@::value_type : view_interface { - private: - chunk_view* @\exposid{parent_}@; // \expos - - constexpr explicit value_type(chunk_view& parent); // \expos - - public: - constexpr @\exposid{inner-iterator}@ begin() const noexcept; - constexpr default_sentinel_t end() const noexcept; - - constexpr auto size() const - requires @\libconcept{sized_sentinel_for}@, iterator_t>; - }; +if (x > 0) { + ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * (x - 1)); + @\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@, @\exposid{end_}@); +} else if (x < 0) { + ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * x + @\exposid{missing_}@); + @\exposid{missing_}@ = 0; } +return *this; \end{codeblock} - -\begin{itemdecl} -constexpr explicit value_type(chunk_view& parent); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} +\indexlibrarymember{operator-=}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{inner-iterator}@ begin() const noexcept; +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{\exposid{inner-iterator}(*\exposid{parent_})}. +\effects +Equivalent to: \tcode{return *this += -x;} \end{itemdescr} +\indexlibrarymember{operator[]}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr default_sentinel_t end() const noexcept; +constexpr value_type operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{default_sentinel}. -\end{itemdescr} - -\begin{itemdecl} -constexpr auto size() const - requires @\libconcept{sized_sentinel_for}@, iterator_t>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return @\exposid{to-unsigned-like}@(ranges::min(@\exposid{parent_}@->@\exposid{remainder_}@, - ranges::end(@\exposid{parent_}@->@\exposid{base_}@) - *@\exposid{parent_}@->@\exposid{current_}@)); -\end{codeblock} -\end{itemdescr} - -\rSec3[range.chunk.inner.iter]{Class \tcode{chunk_view::\exposid{inner-iterator}}} - -\indexlibraryglobal{chunk_view::inner-iterator}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{input_range}@ - class chunk_view::@\exposid{inner-iterator}@ { - chunk_view* @\exposid{parent_}@; // \expos - - constexpr explicit @\exposid{inner-iterator}@(chunk_view& parent) noexcept; // \expos - - public: - using iterator_concept = input_iterator_tag; - using difference_type = range_difference_t; - using value_type = range_value_t; - - @\exposid{inner-iterator}@(@\exposid{inner-iterator}@&&) = default; - @\exposid{inner-iterator}@& operator=(@\exposid{inner-iterator}@&&) = default; - - constexpr const iterator_t& base() const &; - - constexpr range_reference_t operator*() const; - constexpr @\exposid{inner-iterator}@& operator++(); - constexpr void operator++(int); - - friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); - - friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{inner-iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; - friend constexpr difference_type operator-(const @\exposid{inner-iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; - - friend constexpr range_rvalue_reference_t iter_move(const @\exposid{inner-iterator}@& i) - noexcept(noexcept(ranges::iter_move(*i.@\exposid{parent_}@->@\exposid{current_}@))); - - friend constexpr void iter_swap(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) - noexcept(noexcept(ranges::iter_swap(*x.@\exposid{parent_}@->@\exposid{current_}@, *y.@\exposid{parent_}@->@\exposid{current_}@))) - requires @\libconcept{indirectly_swappable}@>; - }; -} -\end{codeblock} +\tcode{*(*this + n)}. +\end{itemdescr} +\indexlibrarymember{operator-=}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{inner-iterator}@(chunk_view& parent) noexcept; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}. +\returns +\tcode{x.\exposid{current_} == y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator==}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr const iterator_t& base() const &; +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return *\exposid{parent_}->\exposid{current_};} +\returns +\tcode{x.\exposid{current_} == x.\exposid{end_}}. \end{itemdescr} +\indexlibrarymember{operator<}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr range_reference_t operator*() const; +friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{*this == default_sentinel} is \tcode{false}. +\returns +\tcode{x.\exposid{current_} < y.\exposid{current_}}. +\end{itemdescr} + +\indexlibrarymember{operator>}{chunk_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} +\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return **\exposid{parent_}->\exposid{current_};} +Equivalent to: \tcode{return y < x;} \end{itemdescr} +\indexlibrarymember{operator<=}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{inner-iterator}@& operator++(); +friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{*this == default_sentinel} is \tcode{false}. - \pnum \effects -Equivalent to: -\begin{codeblock} -++*@\exposid{parent_}@->@\exposid{current_}@; -if (*@\exposid{parent_}@->@\exposid{current_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) - @\exposid{parent_}@->@\exposid{remainder_}@ = 0; -else - --@\exposid{parent_}@->@\exposid{remainder_}@; -return *this; -\end{codeblock} +Equivalent to: \tcode{return !(y < x);} \end{itemdescr} +\indexlibrarymember{operator>=}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -constexpr void operator++(int); +friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{++*this}. +Equivalent to: \tcode{return !(x < y);} \end{itemdescr} +\indexlibrarymember{operator<=>}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && + @\libconcept{three_way_comparable}@>; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{parent_}->\exposid{remainder_} == 0}. +\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator+}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{inner-iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -12791,121 +14716,277 @@ \effects Equivalent to: \begin{codeblock} -return ranges::min(x.@\exposid{parent_}@->@\exposid{remainder_}@, - ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) - *x.@\exposid{parent_}@->@\exposid{current_}@); +auto r = i; +r += n; +return r; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{inner-iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return -(y - x);} +Equivalent to: +\begin{codeblock} +auto r = i; +r -= n; +return r; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr range_rvalue_reference_t iter_move(const @\exposid{inner-iterator}@& i) - noexcept(noexcept(ranges::iter_move(*i.@\exposid{parent_}@->@\exposid{current_}@))); +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return ranges::iter_move(*i.\exposid{parent_}->\exposid{current_});} +\returns +\tcode{(x.\exposid{current_} - y.\exposid{current_} + x.\exposid{missing_} - y.\exposid{missing_}) / x.\exposid{n_}}. \end{itemdescr} +\indexlibrarymember{operator-}{chunk_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr void iter_swap(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) - noexcept(noexcept(ranges::iter_swap(*x.@\exposid{parent_}@->@\exposid{current_}@, *y.@\exposid{parent_}@->@\exposid{current_}@))) - requires @\libconcept{indirectly_swappable}@>; +friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{div-ceil}(x.\exposid{end_} - x.\exposid{current_}, x.\exposid{n_})}. +\end{itemdescr} + +\indexlibrarymember{operator-}{chunk_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{ranges::iter_swap(*x.\exposid{parent_}->\exposid{current_}, *y.\exposid{parent_}->\exposid{current_});} +Equivalent to: \tcode{return -(y - x);} \end{itemdescr} -\rSec3[range.chunk.view.fwd]{Class template \tcode{chunk_view} for forward ranges} +\rSec2[range.slide]{Slide view} -\indexlibrarymember{begin}{chunk_view}% -\indexlibrarymember{end}{chunk_view}% -\indexlibrarymember{size}{chunk_view}% +\rSec3[range.slide.overview]{Overview} + +\pnum +\tcode{slide_view} takes a view and a number $N$ and +produces a view +whose $M^\text{th}$ element is a view over +the $M^\text{th}$ through +$(M + N - 1)^\text{th}$ elements +of the original view. +If the original view has fewer than $N$ elements, +the resulting view is empty. + +\pnum +\indexlibrarymember{slide}{views}% +The name \tcode{views::slide} denotes +a range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{N}, +the expression \tcode{views::slide(E, N)} is expression-equivalent to +\tcode{slide_view(E, N)}. +\begin{example} +\begin{codeblock} +vector v = {1, 2, 3, 4}; + +for (auto i : v | views::slide(2)) { + cout << '[' << i[0] << ", " << i[1] << "] "; // prints \tcode{[1, 2] [2, 3] [3, 4]} +} +\end{codeblock} +\end{example} + +\rSec3[range.slide.view]{Class template \tcode{slide_view}} + +\indexlibraryglobal{slide_view}% +\indexlibraryctor{slide_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{forward_range}@ - class chunk_view : public view_interface> { + template + concept @\defexposconcept{slide-caches-nothing}@ = @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; // \expos + + template + concept @\defexposconcept{slide-caches-last}@ = // \expos + !@\exposconcept{slide-caches-nothing}@ && @\libconcept{bidirectional_range}@ && @\libconcept{common_range}@; + + template + concept @\defexposconcept{slide-caches-first}@ = // \expos + !@\exposconcept{slide-caches-nothing}@ && !@\exposconcept{slide-caches-last}@; + + template<@\libconcept{forward_range}@ V> + requires @\libconcept{view}@ + class slide_view : public view_interface> { V @\exposid{base_}@; // \expos range_difference_t @\exposid{n_}@; // \expos - // \ref{range.chunk.fwd.iter}, class template \tcode{chunk_view::\exposid{iterator}} + // \ref{range.slide.iterator}, class template \tcode{slide_view::\exposid{iterator}} template class @\exposid{iterator}@; // \expos + // \ref{range.slide.sentinel}, class \tcode{slide_view::\exposid{sentinel}} + class @\exposid{sentinel}@; // \expos + public: - constexpr explicit chunk_view(V base, range_difference_t n); + constexpr explicit slide_view(V base, range_difference_t n); constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } constexpr V base() && { return std::move(@\exposid{base_}@); } - constexpr auto begin() requires (!@\exposconcept{simple-view}@) { - return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); - } + constexpr auto begin() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); + constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; - constexpr auto begin() const requires @\libconcept{forward_range}@ { - return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); - } + constexpr auto end() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); + constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; - constexpr auto end() requires (!@\exposconcept{simple-view}@) { - if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@) { - auto missing = (@\exposid{n_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{n_}@) % @\exposid{n_}@; - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); - } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); - } else { - return default_sentinel; - } - } + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; - constexpr auto end() const requires @\libconcept{forward_range}@ { - if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@) { - auto missing = (@\exposid{n_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{n_}@) % @\exposid{n_}@; - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); - } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); - } else { - return default_sentinel; - } - } + constexpr auto reserve_hintsize() requires @\libconcept{approximately_sized_range}@; + constexpr auto reserve_hintsize() const requires @\libconcept{approximately_sized_range}@; + }; + + template + slide_view(R&&, range_difference_t) -> slide_view>; +} +\end{codeblock} + +\indexlibraryctor{slide_view}% +\begin{itemdecl} +constexpr explicit slide_view(V base, range_difference_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{n > 0} is \tcode{true}. + +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{n_} with \tcode{n}. +\end{itemdescr} + +\indexlibrarymember{begin}{slide_view}% +\begin{itemdecl} +constexpr auto begin() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item +If \tcode{V} models \exposconcept{slide-caches-first}, +\begin{codeblock} +@\exposid{iterator}@(ranges::begin(@\exposid{base_}@), + ranges::next(ranges::begin(@\exposid{base_}@), @\exposid{n_}@ - 1, ranges::end(@\exposid{base_}@)), @\exposid{n_}@) +\end{codeblock} +\item +Otherwise, \tcode{\exposid{iterator}(ranges::begin(\exposid{base_}), \exposid{n_})}. +\end{itemize} + +\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{slide_view} +for use on subsequent calls +when \tcode{V} models \exposconcept{slide-caches-first}. +\end{itemdescr} + +\indexlibrarymember{begin}{slide_view}% +\begin{itemdecl} +constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{iterator}(ranges::begin(\exposid{base_}), \exposid{n_})}. +\end{itemdescr} - constexpr auto size() requires @\libconcept{sized_range}@; - constexpr auto size() const requires @\libconcept{sized_range}@; - }; -} +\indexlibrarymember{end}{slide_view}% +\begin{itemdecl} +constexpr auto end() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item +If \tcode{V} models \exposconcept{slide-caches-nothing}, +\begin{codeblock} +@\exposid{iterator}@(ranges::begin(@\exposid{base_}@) + range_difference_t(size()), @\exposid{n_}@) +\end{codeblock} +\item +Otherwise, if \tcode{V} models \exposconcept{slide-caches-last}, +\begin{codeblock} +@\exposid{iterator}@(ranges::prev(ranges::end(@\exposid{base_}@), @\exposid{n_}@ - 1, ranges::begin(@\exposid{base_}@)), @\exposid{n_}@) +\end{codeblock} +\item +Otherwise, if \tcode{V} models \libconcept{common_range}, +\begin{codeblock} +@\exposid{iterator}@(ranges::end(@\exposid{base_}@), ranges::end(@\exposid{base_}@), @\exposid{n_}@) \end{codeblock} +\item +Otherwise, \tcode{\exposid{sentinel}(ranges::end(\exposid{base_}))}. +\end{itemize} + +\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{slide_view} +for use on subsequent calls +when \tcode{V} models \exposconcept{slide-caches-last}. +\end{itemdescr} +\indexlibrarymember{end}{slide_view}% \begin{itemdecl} -constexpr explicit chunk_view(V base, range_difference_t n); +constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{n > 0} is \tcode{true}. +\returns +\tcode{begin() + range_difference_t(size())}. +\end{itemdescr} + +\indexlibrarymember{size}{slide_view}% +\begin{itemdecl} +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; +\end{itemdecl} +\begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{n_} with \tcode{n}. +Equivalent to: +\begin{codeblock} +auto sz = ranges::distance(@\exposid{base_}@) - @\exposid{n_}@ + 1; +if (sz < 0) sz = 0; +return @\exposid{to-unsigned-like}@(sz); +\end{codeblock} \end{itemdescr} +\indexlibrarymember{reserve_hint}{slide_view}% \begin{itemdecl} -constexpr auto size() requires @\libconcept{sized_range}@; -constexpr auto size() const requires @\libconcept{sized_range}@; +constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; +constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; \end{itemdecl} \begin{itemdescr} @@ -12913,43 +14994,46 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); +auto sz = static_cast>(ranges::reserve_hint(@\exposid{base_}@)) - + @\exposid{n_}@ + 1; +if (sz < 0) sz = 0; +return @\exposid{to-unsigned-like}@(sz); \end{codeblock} \end{itemdescr} -\rSec3[range.chunk.fwd.iter]{Class template \tcode{chunk_view::\exposid{iterator}} for forward ranges} +\rSec3[range.slide.iterator]{Class template \tcode{slide_view::\exposid{iterator}}} +\indexlibraryglobal{slide_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{forward_range}@ + template<@\libconcept{forward_range}@ V> + requires @\libconcept{view}@ template - class chunk_view::@\exposid{iterator}@ { - using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + class slide_view::@\exposid{iterator}@ { + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos + iterator_t<@\exposid{Base}@> @\exposid{last_ele_}@ = iterator_t<@\exposid{Base}@>(); // \expos, + // present only if \exposid{Base} models \tcode{\exposconcept{slide-caches-first}} + range_difference_t<@\exposid{Base}@> @\exposid{n_}@ = 0; // \expos - iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos - sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos - range_difference_t<@\exposid{Base}@> @\exposid{n_}@ = 0; // \expos - range_difference_t<@\exposid{Base}@> @\exposid{missing_}@ = 0; // \expos + constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, range_difference_t<@\exposid{Base}@> n) // \expos + requires (!@\exposconcept{slide-caches-first}@<@\exposid{Base}@>); - constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, // \expos - range_difference_t<@\exposid{Base}@> missing = 0); + constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, iterator_t<@\exposid{Base}@> last_ele, // \expos + range_difference_t<@\exposid{Base}@> n) + requires @\exposconcept{slide-caches-first}@<@\exposid{Base}@>; public: using iterator_category = input_iterator_tag; using iterator_concept = @\seebelow@; - using value_type = decltype(views::take(subrange(@\exposid{current_}@, @\exposid{end_}@), @\exposid{n_}@)); + using value_type = decltype(views::counted(@\exposid{current_}@, @\exposid{n_}@)); using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{iterator}@() = default; constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> - && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; - - constexpr iterator_t<@\exposid{Base}@> base() const; + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; - constexpr value_type operator*() const; + constexpr auto operator*() const; constexpr @\exposid{iterator}@& operator++(); constexpr @\exposid{iterator}@ operator++(int); @@ -12961,11 +15045,10 @@ constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr value_type operator[](difference_type n) const + constexpr auto operator[](difference_type n) const requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); - friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -12987,11 +15070,6 @@ requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; - - friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; }; } \end{codeblock} @@ -13009,59 +15087,68 @@ Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. \end{itemize} +\pnum +If the invocation of any non-const member function of \exposid{iterator} +exits via an exception, the \exposid{iterator} acquires a singular value. + +\indexlibraryctor{slide_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, - range_difference_t<@\exposid{Base}@> missing = 0); +constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, range_difference_t<@\exposid{Base}@> n) + requires (!@\exposconcept{slide-caches-first}@<@\exposid{Base}@>); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{current}, -\exposid{end_} with \tcode{ranges::end(parent->\exposid{base_})}, -\exposid{n_} with \tcode{parent\linebreak ->\exposid{n_}}, and -\exposid{missing_} with \tcode{missing}. +Initializes \exposid{current_} with \tcode{current} and +\exposid{n_} with \tcode{n}. \end{itemdescr} +\indexlibraryctor{slide_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> - && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, iterator_t<@\exposid{Base}@> last_ele, + range_difference_t<@\exposid{Base}@> n) + requires @\exposconcept{slide-caches-first}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}, -\exposid{end_} with \tcode{std::move(i.\exposid{end_})}, -\exposid{n_} with \tcode{i.\exposid{n_}}, and -\exposid{missing_} with \tcode{i.\exposid{missing_}}. +Initializes \exposid{current_} with \tcode{current}, +\exposid{last_ele_} with \tcode{last_ele}, and +\exposid{n_} with \tcode{n}. \end{itemdescr} +\indexlibraryctor{slide_view::\exposid{iterator}}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() const; +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\exposid{current_}. +\effects +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})} and +\exposid{n_} with \tcode{i.\exposid{n_}}. +\begin{note} +\tcode{\exposid{iterator}} can only be formed +when \exposid{Base} models \exposconcept{slide-caches-nothing}, +in which case \exposid{last_ele_} is not present. +\end{note} \end{itemdescr} +\indexlibrarymember{operator*}{slide_view::\exposid{iterator}}% \begin{itemdecl} -constexpr value_type operator*() const; +constexpr auto operator*() const; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. - \pnum \returns -\tcode{views::take(subrange(\exposid{current_}, \exposid{end_}), \exposid{n_})}. +\tcode{views::counted(\exposid{current_}, \exposid{n_})}. \end{itemdescr} +\indexlibrarymember{operator++}{slide_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -13069,17 +15156,20 @@ \begin{itemdescr} \pnum \expects -\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. +\exposid{current_} and \exposid{last_ele_} (if present) are incrementable. \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@, @\exposid{end_}@); -return *this; -\end{codeblock} +\ensures +\exposid{current_} and \exposid{last_ele_} (if present) are +each equal to \tcode{ranges::next(i)}, +where \tcode{i} is the value of that data member before the call. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator++}{slide_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} @@ -13095,21 +15185,28 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{slide_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -ranges::advance(@\exposid{current_}@, @\exposid{missing_}@ - @\exposid{n_}@); -@\exposid{missing_}@ = 0; -return *this; -\end{codeblock} +\expects +\exposid{current_} and \exposid{last_ele_} (if present) are decrementable. + +\pnum +\ensures +\exposid{current_} and \exposid{last_ele_} (if present) are +each equal to \tcode{ranges::prev(i)}, +where \tcode{i} is the value of that data member before the call. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator--}{slide_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} @@ -13125,6 +15222,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{slide_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13133,28 +15231,21 @@ \begin{itemdescr} \pnum \expects -If \tcode{x} is positive, -\tcode{ranges::distance(\exposid{current_}, \exposid{end_}) > \exposid{n_} * (x - 1)} -is \tcode{true}. -\begin{note} -If \tcode{x} is negative, the \Fundescx{Effects} paragraph implies a precondition. -\end{note} +\tcode{\exposid{current_} + x} and \tcode{\exposid{last_ele_} + x} (if \exposid{last_ele_} is present) +have well-defined behavior. \pnum -\effects -Equivalent to: -\begin{codeblock} -if (x > 0) { - ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * (x - 1)); - @\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@, @\exposid{end_}@); -} else if (x < 0) { - ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * x + @\exposid{missing_}@); - @\exposid{missing_}@ = 0; -} -return *this; -\end{codeblock} +\ensures +\exposid{current_} and \exposid{last_ele_} (if present) are +each equal to \tcode{i + x}, +where \tcode{i} is the value of that data member before the call. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator-=}{slide_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13162,41 +15253,47 @@ \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return *this += -x;} -\end{itemdescr} +\expects +\tcode{\exposid{current_} - x} and \tcode{\exposid{last_ele_} - x} (if \exposid{last_ele_} is present) +have well-defined behavior. -\begin{itemdecl} -constexpr value_type operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} +\pnum +\ensures +\exposid{current_} and \exposid{last_ele_} (if present) are +each equal to \tcode{i - x}, +where \tcode{i} is the value of that data member before the call. -\begin{itemdescr} \pnum \returns -\tcode{*(*this + n)}. +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator[]}{slide_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +constexpr auto operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} == y.\exposid{current_}}. +\effects +Equivalent to: \tcode{return views::counted(\exposid{current_} + n, \exposid{n_});} \end{itemdescr} +\indexlibrarymember{operator==}{slide_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{current_} == x.\exposid{end_}}. +If \exposid{last_ele_} is present, +\tcode{x.\exposid{last_ele_} == y.\exposid{last_ele_}}; +otherwise, \tcode{x.\exposid{current_} == y.\exposid{cur\-rent_}}. \end{itemdescr} +\indexlibrarymember{operator<}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13208,6 +15305,7 @@ \tcode{x.\exposid{current_} < y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator>}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13219,6 +15317,7 @@ Equivalent to: \tcode{return y < x;} \end{itemdescr} +\indexlibrarymember{operator<=}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13230,6 +15329,7 @@ Equivalent to: \tcode{return !(y < x);} \end{itemdescr} +\indexlibrarymember{operator>=}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13241,6 +15341,7 @@ Equivalent to: \tcode{return !(x < y);} \end{itemdescr} +\indexlibrarymember{operator<=>}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @@ -13253,6 +15354,7 @@ \tcode{x.\exposid{current_} <=> y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator+}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13271,6 +15373,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -13287,6 +15390,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-}{slide_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; @@ -13295,299 +15399,302 @@ \begin{itemdescr} \pnum \returns -\tcode{(x.\exposid{current_} - y.\exposid{current_} + x.\exposid{missing_} - y.\exposid{missing_}) / x.\exposid{n_}}. +If \exposid{last_ele_} is present, +\tcode{x.\exposid{last_ele_} - y.\exposid{last_ele_}}; +otherwise, \tcode{x.\exposid{current_} - y.\exposid{cur\-rent_}}. +\end{itemdescr} + +\rSec3[range.slide.sentinel]{Class \tcode{slide_view::\exposid{sentinel}}} + +\indexlibraryglobal{slide_view::\exposid{sentinel}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{forward_range}@ V> + requires @\libconcept{view}@ + class slide_view::@\exposid{sentinel}@ { + sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos + constexpr explicit @\exposid{sentinel}@(sentinel_t end); // \expos + + public: + @\exposid{sentinel}@() = default; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + + friend constexpr range_difference_t + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + + friend constexpr range_difference_t + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + }; +} +\end{codeblock} + +\pnum +\begin{note} +\exposid{sentinel} is used +only when \tcode{\exposconcept{slide-caches-first}} is \tcode{true}. +\end{note} + +\indexlibraryctor{slide_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(sentinel_t end); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{end}. \end{itemdescr} +\indexlibrarymember{operator==}{slide_view::\exposid{sentinel}}% \begin{itemdecl} -friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{\exposid{div-ceil}(x.\exposid{end_} - x.\exposid{current_}, x.\exposid{n_})}. +\tcode{x.\exposid{last_ele_} == y.\exposid{end_}}. \end{itemdescr} +\indexlibrarymember{operator-}{slide_view::\exposid{sentinel}}% \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; +friend constexpr range_difference_t + operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return -(y - x);} +\returns +\tcode{x.\exposid{last_ele_} - y.\exposid{end_}}. \end{itemdescr} -\rSec2[range.slide]{Slide view} +\indexlibrarymember{operator-}{slide_view::\exposid{sentinel}}% +\begin{itemdecl} +friend constexpr range_difference_t + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; +\end{itemdecl} -\rSec3[range.slide.overview]{Overview} +\begin{itemdescr} +\pnum +\returns +\tcode{y.\exposid{end_} - x.\exposid{last_ele_}}. +\end{itemdescr} + +\rSec2[range.chunk.by]{Chunk by view} + +\rSec3[range.chunk.by.overview]{Overview} \pnum -\tcode{slide_view} takes a view and a number $N$ and -produces a view -whose $M^\text{th}$ element is a view over -the $M^\text{th}$ through -$(M + N - 1)^\text{th}$ elements -of the original view. -If the original view has fewer than $N$ elements, -the resulting view is empty. +\tcode{chunk_by_view} takes a view and a predicate, and +splits the view into \tcode{subrange}s +between each pair of adjacent elements +for which the predicate returns \tcode{false}. \pnum -\indexlibrarymember{slide}{views}% -The name \tcode{views::slide} denotes +\indexlibrarymember{chunk_by}{views}% +The name \tcode{views::chunk_by} denotes a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{N}, -the expression \tcode{views::slide(E, N)} is expression-equivalent to -\tcode{slide_view(E, N)}. +Given subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::chunk_by(E, F)} is expression-equivalent to +\tcode{chunk_by_view(E, F)}. \begin{example} \begin{codeblock} -vector v = {1, 2, 3, 4}; +vector v = {1, 2, 2, 3, 0, 4, 5, 2}; -for (auto i : v | views::slide(2)) { - cout << '[' << i[0] << ", " << i[1] << "] "; // prints \tcode{[1, 2] [2, 3] [3, 4]} +for (auto r : v | views::chunk_by(ranges::less_equal{})) { + cout << '['; + auto sep = ""; + for (auto i : r) { + cout << sep << i; + sep = ", "; + } + cout << "] "; } +// The above prints \tcode{[1, 2, 2, 3] [0, 4, 5] [2]} \end{codeblock} \end{example} -\rSec3[range.slide.view]{Class template \tcode{slide_view}} +\rSec3[range.chunk.by.view]{Class template \tcode{chunk_by_view}} -\indexlibrarymember{begin}{slide_view}% -\indexlibrarymember{end}{slide_view}% -\indexlibrarymember{size}{slide_view}% +\indexlibraryglobal{chunk_by_view}% \begin{codeblock} namespace std::ranges { - template - concept @\defexposconcept{slide-caches-nothing}@ = @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; // \expos - - template - concept @\defexposconcept{slide-caches-last}@ = // \expos - !@\exposconcept{slide-caches-nothing}@ && @\libconcept{bidirectional_range}@ && @\libconcept{common_range}@; - - template - concept @\defexposconcept{slide-caches-first}@ = // \expos - !@\exposconcept{slide-caches-nothing}@ && !@\exposconcept{slide-caches-last}@; - - template<@\libconcept{forward_range}@ V> - requires @\libconcept{view}@ - class slide_view : public view_interface> { - V @\exposid{base_}@; // \expos - range_difference_t @\exposid{n_}@; // \expos - - // \ref{range.slide.iterator}, class template \tcode{slide_view::\exposid{iterator}} - template class @\exposid{iterator}@; // \expos + template<@\libconcept{forward_range}@ V, @\libconcept{indirect_binary_predicate}@, iterator_t> Pred> + requires @\libconcept{view}@ && is_object_v + class chunk_by_view : public view_interface> { + V @\exposid{base_}@ = V(); // \expos + @\exposidnc{movable-box}@ @\exposid{pred_}@; // \expos - // \ref{range.slide.sentinel}, class \tcode{slide_view::\exposid{sentinel}} - class @\exposid{sentinel}@; // \expos + // \ref{range.chunk.by.iter}, class \tcode{chunk_by_view::\exposid{iterator}} + class @\exposidnc{iterator}@; // \expos public: - constexpr explicit slide_view(V base, range_difference_t n); + chunk_by_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr explicit chunk_by_view(V base, Pred pred); constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } constexpr V base() && { return std::move(@\exposid{base_}@); } - constexpr auto begin() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); - constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; + constexpr const Pred& pred() const; - constexpr auto end() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); - constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; + constexpr @\exposid{iterator}@ begin(); + constexpr auto end(); - constexpr auto size() requires @\libconcept{sized_range}@; - constexpr auto size() const requires @\libconcept{sized_range}@; + constexpr iterator_t @\exposidnc{find-next}@(iterator_t); // \expos + constexpr iterator_t @\exposidnc{find-prev}@(iterator_t) // \expos + requires @\libconcept{bidirectional_range}@; }; - template - slide_view(R&&, range_difference_t) -> slide_view>; + template + chunk_by_view(R&&, Pred) -> chunk_by_view, Pred>; } \end{codeblock} +\indexlibraryctor{chunk_by_view}% \begin{itemdecl} -constexpr explicit slide_view(V base, range_difference_t n); +constexpr explicit chunk_by_view(V base, Pred pred); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{n > 0} is \tcode{true}. - \pnum \effects Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{n_} with \tcode{n}. +\exposid{pred_} with \tcode{std::move(pred)}. \end{itemdescr} +\indexlibrarymember{pred}{chunk_by_view}% \begin{itemdecl} -constexpr auto begin() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); +constexpr const Pred& pred() const; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\begin{itemize} -\item -If \tcode{V} models \exposconcept{slide-caches-first}, -\begin{codeblock} -@\exposid{iterator}@(ranges::begin(@\exposid{base_}@), - ranges::next(ranges::begin(@\exposid{base_}@), @\exposid{n_}@ - 1, ranges::end(@\exposid{base_}@)), @\exposid{n_}@) -\end{codeblock} -\item -Otherwise, \tcode{\exposid{iterator}(ranges::begin(\exposid{base_}), \exposid{n_})}. -\end{itemize} - -\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{slide_view} -for use on subsequent calls -when \tcode{V} models \exposconcept{slide-caches-first}. +\effects +Equivalent to: \tcode{return *\exposid{pred_};} \end{itemdescr} +\indexlibrarymember{begin}{chunk_by_view}% \begin{itemdecl} -constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; +constexpr @\exposid{iterator}@ begin(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. + \pnum \returns -\tcode{\exposid{iterator}(ranges::begin(\exposid{base_}), \exposid{n_})}. +\tcode{\exposid{iterator}(*this, ranges::begin(\exposid{base_}), \exposid{find-next}(ranges::begin(\exposid{base_})))}. + +\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{chunk_by_view} +for use on subsequent calls. \end{itemdescr} +\indexlibrarymember{end}{chunk_by_view}% \begin{itemdecl} -constexpr auto end() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); +constexpr auto end(); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\begin{itemize} -\item -If \tcode{V} models \exposconcept{slide-caches-nothing}, -\begin{codeblock} -@\exposid{iterator}@(ranges::begin(@\exposid{base_}@) + range_difference_t(size()), @\exposid{n_}@) -\end{codeblock} -\item -Otherwise, if \tcode{V} models \exposconcept{slide-caches-last}, -\begin{codeblock} -@\exposid{iterator}@(ranges::prev(ranges::end(@\exposid{base_}@), @\exposid{n_}@ - 1, ranges::begin(@\exposid{base_}@)), @\exposid{n_}@) -\end{codeblock} -\item -Otherwise, if \tcode{V} models \libconcept{common_range}, +\effects +Equivalent to: \begin{codeblock} -@\exposid{iterator}@(ranges::end(@\exposid{base_}@), ranges::end(@\exposid{base_}@), @\exposid{n_}@) +if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@(*this, ranges::end(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); +} else { + return default_sentinel; +} \end{codeblock} -\item -Otherwise, \tcode{\exposid{sentinel}(ranges::end(\exposid{base_}))}. -\end{itemize} - -\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{slide_view} -for use on subsequent calls -when \tcode{V} models \exposconcept{slide-caches-last}. \end{itemdescr} \begin{itemdecl} -constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; +constexpr iterator_t @\exposid{find-next}@(iterator_t current); \end{itemdecl} -\begin{itemdescr} +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. + \pnum \returns -\tcode{begin() + range_difference_t(size())}. +\begin{codeblock} +ranges::next(ranges::adjacent_find(current, ranges::end(@\exposid{base_}@), not_fn(ref(*@\exposid{pred_}@))), + 1, ranges::end(@\exposid{base_}@)) +\end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr auto size() requires @\libconcept{sized_range}@; -constexpr auto size() const requires @\libconcept{sized_range}@; +constexpr iterator_t @\exposid{find-prev}@(iterator_t current) requires @\libconcept{bidirectional_range}@; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto sz = ranges::distance(@\exposid{base_}@) - @\exposid{n_}@ + 1; -if (sz < 0) sz = 0; -return @\exposid{to-unsigned-like}@(sz); -\end{codeblock} +\expects +\begin{itemize} +\item +\tcode{current} is not equal to \tcode{ranges::begin(\exposid{base_})}. +\item +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. +\end{itemize} + +\pnum +\returns +An iterator \tcode{i} +in the range \range{ranges::begin(\exposid{base_})}{current} such that: +\begin{itemize} +\item +\tcode{ranges::adjacent_find(i, current, not_fn(ref(*\exposid{pred_})))} is equal to \tcode{current}; and +\item +if \tcode{i} is not equal to \tcode{ranges::begin(\exposid{base_})}, +then \tcode{bool(invoke(*\exposid{pred_}, *ranges::prev(i), *i))} +is \tcode{false}. +\end{itemize} \end{itemdescr} -\rSec3[range.slide.iterator]{Class template \tcode{slide_view::\exposid{iterator}}} +\rSec3[range.chunk.by.iter]{Class \tcode{chunk_by_view::\exposid{iterator}}} +\indexlibraryglobal{chunk_by_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V> - requires @\libconcept{view}@ - template - class slide_view::@\exposid{iterator}@ { - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos - iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos - iterator_t<@\exposid{Base}@> @\exposid{last_ele_}@ = iterator_t<@\exposid{Base}@>(); // \expos, - // present only if \exposid{Base} models \tcode{\exposconcept{slide-caches-first}} - range_difference_t<@\exposid{Base}@> @\exposid{n_}@ = 0; // \expos - - constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, range_difference_t<@\exposid{Base}@> n) // \expos - requires (!@\exposconcept{slide-caches-first}@<@\exposid{Base}@>); + template<@\libconcept{forward_range}@ V, @\libconcept{indirect_binary_predicate}@, iterator_t> Pred> + requires @\libconcept{view}@ && is_object_v + class chunk_by_view::@\exposid{iterator}@ { + chunk_by_view* @\exposid{parent_}@ = nullptr; // \expos + iterator_t @\exposid{current_}@ = iterator_t(); // \expos + iterator_t @\exposid{next_}@ = iterator_t(); // \expos - constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, iterator_t<@\exposid{Base}@> last_ele, // \expos - range_difference_t<@\exposid{Base}@> n) - requires @\exposconcept{slide-caches-first}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, // \expos + iterator_t next); public: + using value_type = subrange>; + using difference_type = range_difference_t; using iterator_category = input_iterator_tag; using iterator_concept = @\seebelow@; - using value_type = decltype(views::counted(@\exposid{current_}@, @\exposid{n_}@)); - using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{iterator}@() = default; - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; - constexpr auto operator*() const; + constexpr value_type operator*() const; constexpr @\exposid{iterator}@& operator++(); constexpr @\exposid{iterator}@ operator++(int); - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - - constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - - constexpr auto operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); - - friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && - @\libconcept{three_way_comparable}@>; - - friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); }; } \end{codeblock} @@ -13596,72 +15703,41 @@ \tcode{\exposid{iterator}::iterator_concept} is defined as follows: \begin{itemize} \item -If \exposid{Base} models \libconcept{random_access_range}, -then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. -\item -Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, +If \tcode{V} models \libconcept{bidirectional_range}, then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. \item Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. \end{itemize} -\pnum -If the invocation of any non-const member function of \exposid{iterator} -exits via an exception, the \exposid{iterator} acquires a singular value. - -\begin{itemdecl} -constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, range_difference_t<@\exposid{Base}@> n) - requires (!@\exposconcept{slide-caches-first}@<@\exposid{Base}@>); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{current_} with \tcode{current} and -\exposid{n_} with \tcode{n}. -\end{itemdescr} - +\indexlibraryctor{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, iterator_t<@\exposid{Base}@> last_ele, - range_difference_t<@\exposid{Base}@> n) - requires @\exposconcept{slide-caches-first}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, iterator_t next); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{current}, -\exposid{last_ele_} with \tcode{last_ele}, and -\exposid{n_} with \tcode{n}. +Initializes \exposid{parent_} with \tcode{addressof(parent)}, +\exposid{current_} with \tcode{current}, and +\exposid{next_} with \tcode{next}. \end{itemdescr} +\indexlibrarymember{operator*}{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +constexpr value_type operator*() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})} and -\exposid{n_} with \tcode{i.\exposid{n_}}. -\begin{note} -\tcode{\exposid{iterator}} can only be formed -when \exposid{Base} models \exposconcept{slide-caches-nothing}, -in which case \exposid{last_ele_} is not present. -\end{note} -\end{itemdescr} - -\begin{itemdecl} -constexpr auto operator*() const; -\end{itemdecl} +\expects +\exposid{current_} is not equal to \exposid{next_}. -\begin{itemdescr} \pnum \returns -\tcode{views::counted(\exposid{current_}, \exposid{n_})}. +\tcode{subrange(\exposid{current_}, \exposid{next_})}. \end{itemdescr} +\indexlibrarymember{operator++}{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -13669,19 +15745,19 @@ \begin{itemdescr} \pnum \expects -\exposid{current_} and \exposid{last_ele_} (if present) are incrementable. - -\pnum -\ensures -\exposid{current_} and \exposid{last_ele_} (if present) are -each equal to \tcode{ranges::next(i)}, -where \tcode{i} is the value of that data member before the call. +\exposid{current_} is not equal to \exposid{next_}. \pnum -\returns -\tcode{*this}. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ = @\exposid{next_}@; +@\exposid{next_}@ = @\exposid{parent_}@->@\exposid{find-next}@(@\exposid{current_}@); +return *this; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} @@ -13697,28 +15773,25 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\exposid{current_} and \exposid{last_ele_} (if present) are decrementable. - -\pnum -\ensures -\exposid{current_} and \exposid{last_ele_} (if present) are -each equal to \tcode{ranges::prev(i)}, -where \tcode{i} is the value of that data member before the call. - -\pnum -\returns -\tcode{*this}. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{next_}@ = @\exposid{current_}@; +@\exposid{current_}@ = @\exposid{parent_}@->@\exposid{find-prev}@(@\exposid{next_}@); +return *this; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; \end{itemdecl} \begin{itemdescr} @@ -13732,134 +15805,146 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator==}{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{\exposid{current_} + x} and \tcode{\exposid{last_ele_} + x} (if \exposid{last_ele_} is present) -have well-defined behavior. - -\pnum -\ensures -\exposid{current_} and \exposid{last_ele_} (if present) are -each equal to \tcode{i + x}, -where \tcode{i} is the value of that data member before the call. - \pnum \returns -\tcode{*this}. +\tcode{x.\exposid{current_} == y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator==}{chunk_by_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{\exposid{current_} - x} and \tcode{\exposid{last_ele_} - x} (if \exposid{last_ele_} is present) -have well-defined behavior. +\returns +\tcode{x.\exposid{current_} == x.\exposid{next_}}. +\end{itemdescr} + +\rSec2[range.stride]{Stride view} + +\rSec3[range.stride.overview]{Overview} \pnum -\ensures -\exposid{current_} and \exposid{last_ele_} (if present) are -each equal to \tcode{i - x}, -where \tcode{i} is the value of that data member before the call. +\tcode{stride_view} presents a view of an underlying sequence, +advancing over $n$ elements at a time, +as opposed to the usual single-step succession. + +\pnum +The name \tcode{views::stride} denotes +a range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{N}, +the expression \tcode{views::stride(E, N)} +is expression-equivalent to \tcode{stride_view(E, N)}. + +\pnum +\begin{example} +\begin{codeblock} +auto input = views::iota(0, 12) | views::stride(3); +ranges::copy(input, ostream_iterator(cout, " ")); // prints \tcode{0 3 6 9} +ranges::copy(input | views::reverse, ostream_iterator(cout, " ")); // prints \tcode{9 6 3 0} +\end{codeblock} +\end{example} + +\rSec3[range.stride.view]{Class template \tcode{stride_view}} + +\indexlibraryglobal{stride_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class stride_view : public view_interface> { + V @\exposid{base_}@; // \expos + range_difference_t @\exposid{stride_}@; // \expos + // \ref{range.stride.iterator}, class template \tcode{stride_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos + public: + constexpr explicit stride_view(V base, range_difference_t stride); -\pnum -\returns -\tcode{*this}. -\end{itemdescr} + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } -\begin{itemdecl} -constexpr auto operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} + constexpr range_difference_t stride() const noexcept; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return views::counted(\exposid{current_} + n, \exposid{n_});} -\end{itemdescr} + constexpr auto begin() requires (!@\exposconcept{simple-view}@) { + return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); + } -\begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); -\end{itemdecl} + constexpr auto begin() const requires @\libconcept{range}@ { + return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); + } -\begin{itemdescr} -\pnum -\returns -If \exposid{last_ele_} is present, -\tcode{x.\exposid{last_ele_} == y.\exposid{last_ele_}}; -otherwise, \tcode{x.\exposid{current_} == y.\exposid{cur\-rent_}}. -\end{itemdescr} + constexpr auto end() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@ && @\libconcept{forward_range}@) { + auto missing = (@\exposid{stride_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{stride_}@) % @\exposid{stride_}@; + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); + } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); + } else { + return default_sentinel; + } + } -\begin{itemdecl} -friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} + constexpr auto end() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@ && @\libconcept{forward_range}@) { + auto missing = (@\exposid{stride_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{stride_}@) % @\exposid{stride_}@; + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); + } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { + return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); + } else { + return default_sentinel; + } + } -\begin{itemdescr} -\pnum -\returns -\tcode{x.\exposid{current_} < y.\exposid{current_}}. -\end{itemdescr} + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; -\begin{itemdecl} -friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} + constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; + constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; + }; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return y < x;} -\end{itemdescr} + template + stride_view(R&&, range_difference_t) -> stride_view>; +} +\end{codeblock} +\indexlibraryctor{stride_view}% \begin{itemdecl} -friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr stride_view(V base, range_difference_t stride); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return !(y < x);} -\end{itemdescr} - -\begin{itemdecl} -friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} +\expects +\tcode{stride > 0} is \tcode{true}. -\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(x < y);} +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{stride_} with \tcode{stride}. \end{itemdescr} +\indexlibrarymember{stride}{stride_view}% \begin{itemdecl} -friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && - @\libconcept{three_way_comparable}@>; +constexpr range_difference_t stride() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. +\exposid{stride_}. \end{itemdescr} +\indexlibrarymember{size}{stride_view}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; \end{itemdecl} \begin{itemdescr} @@ -13867,15 +15952,14 @@ \effects Equivalent to: \begin{codeblock} -auto r = i; -r += n; -return r; +return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{stride_}@)); \end{codeblock} \end{itemdescr} +\indexlibrarymember{reserve_hint}{stride_view}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; +constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; \end{itemdecl} \begin{itemdescr} @@ -13883,215 +15967,240 @@ \effects Equivalent to: \begin{codeblock} -auto r = i; -r -= n; -return r; +auto s = static_cast>(ranges::reserve_hint(@\exposid{base_}@)); +return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(s, @\exposid{stride_}@)); \end{codeblock} \end{itemdescr} -\begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -If \exposid{last_ele_} is present, -\tcode{x.\exposid{last_ele_} - y.\exposid{last_ele_}}; -otherwise, \tcode{x.\exposid{current_} - y.\exposid{cur\-rent_}}. -\end{itemdescr} - -\rSec3[range.slide.sentinel]{Class \tcode{slide_view::\exposid{sentinel}}} +\rSec3[range.stride.iterator]{Class template \tcode{stride_view::\exposid{iterator}}} +\indexlibraryglobal{stride_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V> + template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ - class slide_view::@\exposid{sentinel}@ { - sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos - constexpr explicit @\exposid{sentinel}@(sentinel_t end); // \expos + template + class stride_view::@\exposid{iterator}@ { + using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + + iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos + sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + range_difference_t<@\exposid{Base}@> @\exposid{stride_}@ = 0; // \expos + range_difference_t<@\exposid{Base}@> @\exposid{missing_}@ = 0; // \expos + constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, // \expos + range_difference_t<@\exposid{Base}@> missing = 0); public: - @\exposid{sentinel}@() = default; + using difference_type = range_difference_t<@\exposid{Base}@>; + using value_type = range_value_t<@\exposid{Base}@>; + using iterator_concept = @\seebelow@; + using iterator_category = @\seebelow@; // not always present - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; - friend constexpr range_difference_t - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; + constexpr @\exposid{iterator}@(@\exposid{iterator}@ other) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> + && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; - friend constexpr range_difference_t - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; + constexpr iterator_t<@\exposid{Base}@> base() &&; + constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; + + constexpr decltype(auto) operator*() const { return *@\exposid{current_}@; } + + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; + + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + + constexpr @\exposid{iterator}@& operator+=(difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@& operator-=(difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + constexpr decltype(auto) operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@> + { return *(*this + n); } + + friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{equality_comparable}@>; + + friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; + + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + + friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + + friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); + + friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) + requires @\libconcept{indirectly_swappable}@>; }; } \end{codeblock} \pnum -\begin{note} -\exposid{sentinel} is used -only when \tcode{\exposconcept{slide-caches-first}} is \tcode{true}. -\end{note} +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +\begin{itemize} +\item +If \exposid{Base} models \libconcept{random_access_range}, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, if \exposid{Base} models \libconcept{forward_range}, +then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\pnum +The member \grammarterm{typedef-name} \tcode{iterator_category} is defined +if and only if \exposid{Base} models \libconcept{forward_range}. +In that case, +\tcode{\exposid{iterator}::iterator_category} is defined as follows: +\begin{itemize} +\item +Let \tcode{C} denote +the type \tcode{iterator_traits>::iterator_category}. +\item +If \tcode{C} models +\tcode{\libconcept{derived_from}}, +then \tcode{iterator_category} denotes \tcode{ran\-dom_access_iterator_tag}. +\item +Otherwise, \tcode{iterator_category} denotes \tcode{C}. +\end{itemize} +\indexlibraryctor{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t end); +constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, + range_difference_t<@\exposid{Base}@> missing = 0); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end}. +Initializes \exposid{current_} with \tcode{std::move(current)}, +\exposid{end_} with \tcode{ranges::end(parent->\exposid{base_})}, +\exposid{stride_} with \tcode{parent->\exposid{stride_}}, and +\exposid{missing_} with \tcode{missing}. \end{itemdescr} +\indexlibraryctor{stride_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> + && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{last_ele_} == y.\exposid{end_}}. +\effects +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}, +\exposid{end_} with \tcode{std::move(i.\exposid{end_})}, +\exposid{stride_} with \tcode{i.\exposid{stride_}}, and +\exposid{missing_} with \tcode{i.\exposid{missing_}}. \end{itemdescr} +\indexlibrarymember{base}{stride_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr range_difference_t - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +constexpr iterator_t<@\exposid{Base}@> base() &&; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{last_ele_} - y.\exposid{end_}}. +\tcode{std::move(\exposid{current_})}. \end{itemdescr} +\indexlibrarymember{base}{stride_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr range_difference_t - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{y.\exposid{end_} - x.\exposid{last_ele_}}. +\exposid{current_}. \end{itemdescr} -\rSec2[range.chunk.by]{Chunk by view} - -\rSec3[range.chunk.by.overview]{Overview} - -\pnum -\tcode{chunk_by_view} takes a view and a predicate, and -splits the view into \tcode{subrange}s -between each pair of adjacent elements -for which the predicate returns \tcode{false}. - -\pnum -\indexlibrarymember{chunk_by}{views}% -The name \tcode{views::chunk_by} denotes -a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{F}, -the expression \tcode{views::chunk_by(E, F)} is expression-equivalent to -\tcode{chunk_by_view(E, F)}. -\begin{example} -\begin{codeblock} -vector v = {1, 2, 2, 3, 0, 4, 5, 2}; - -for (auto r : v | views::chunk_by(ranges::less_equal{})) { - cout << '['; - auto sep = ""; - for (auto i : r) { - cout << sep << i; - sep = ", "; - } - cout << "] "; -} -// The above prints \tcode{[1, 2, 2, 3] [0, 4, 5] [2]} -\end{codeblock} -\end{example} - -\rSec3[range.chunk.by.view]{Class template \tcode{chunk_by_view}} - -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{indirect_binary_predicate}@, iterator_t> Pred> - requires @\libconcept{view}@ && is_object_v - class chunk_by_view : public view_interface> { - V @\exposid{base_}@ = V(); // \expos - @\exposidnc{movable-box}@ @\exposid{pred_}@; // \expos - - // \ref{range.chunk.by.iter}, class \tcode{chunk_by_view::\exposid{iterator}} - class @\exposidnc{iterator}@; // \expos - - public: - chunk_by_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr explicit chunk_by_view(V base, Pred pred); - - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } - - constexpr const Pred& pred() const; - - constexpr @\exposid{iterator}@ begin(); - constexpr auto end(); - - constexpr iterator_t @\exposidnc{find-next}@(iterator_t); // \expos - constexpr iterator_t @\exposidnc{find-prev}@(iterator_t) // \expos - requires @\libconcept{bidirectional_range}@; - }; - - template - chunk_by_view(R&&, Pred) -> chunk_by_view, Pred>; -} -\end{codeblock} - +\indexlibrarymember{operator++}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit chunk_by_view(V base, Pred pred); +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. + \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{pred_} with \tcode{std::move(pred)}. +Equivalent to: +\begin{codeblock} +@\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{stride_}@, @\exposid{end_}@); +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{pred}{chunk_by_view}% +\indexlibrarymember{operator++}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr const Pred& pred() const; +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *\exposid{pred_};} +Equivalent to \tcode{++*this;} \end{itemdescr} +\indexlibrarymember{operator++}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ begin(); +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{\exposid{pred_}.has_value()} is \tcode{true}. - -\pnum -\returns -\tcode{\exposid{iterator}(*this, ranges::begin(\exposid{base_}), \exposid{find-next}(ranges::begin(\exposid{base_})))}. - -\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{chunk_by_view} -for use on subsequent calls. +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr auto end(); +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -14099,583 +16208,630 @@ \effects Equivalent to: \begin{codeblock} -if constexpr (@\libconcept{common_range}@) { - return @\exposid{iterator}@(*this, ranges::end(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); -} else { - return default_sentinel; -} +ranges::advance(@\exposid{current_}@, @\exposid{missing_}@ - @\exposid{stride_}@); +@\exposid{missing_}@ = 0; +return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr iterator_t @\exposid{find-next}@(iterator_t current); +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{\exposid{pred_}.has_value()} is \tcode{true}. - -\pnum -\returns +\effects +Equivalent to: \begin{codeblock} -ranges::next(ranges::adjacent_find(current, ranges::end(@\exposid{base_}@), not_fn(ref(*@\exposid{pred_}@))), - 1, ranges::end(@\exposid{base_}@)) +auto tmp = *this; +--*this; +return tmp; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr iterator_t @\exposid{find-prev}@(iterator_t current) requires @\libconcept{bidirectional_range}@; +constexpr @\exposid{iterator}@& operator+=(difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \expects -\begin{itemize} -\item -\tcode{current} is not equal to \tcode{ranges::begin(\exposid{base_})}. -\item -\tcode{\exposid{pred_}.has_value()} is \tcode{true}. -\end{itemize} +If \tcode{n} is positive, +\tcode{ranges::distance(\exposid{current_}, \exposid{end_}) > \exposid{stride_} * (n - 1)} +is \tcode{true}. +\begin{note} +If \tcode{n} is negative, the \Fundescx{Effects} paragraph implies a precondition. +\end{note} \pnum -\returns -An iterator \tcode{i} -in the range \range{ranges::begin(\exposid{base_})}{current} such that: -\begin{itemize} -\item -\tcode{ranges::adjacent_find(i, current, not_fn(ref(*\exposid{pred_})))} is equal to \tcode{current}; and -\item -if \tcode{i} is not equal to \tcode{ranges::begin(\exposid{base_})}, -then \tcode{bool(invoke(*\exposid{pred_}, *ranges::prev(i), *i))} -is \tcode{false}. -\end{itemize} -\end{itemdescr} - -\rSec3[range.chunk.by.iter]{Class \tcode{chunk_by_view::\exposid{iterator}}} - +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{indirect_binary_predicate}@, iterator_t> Pred> - requires @\libconcept{view}@ && is_object_v - class chunk_by_view::@\exposid{iterator}@ { - chunk_by_view* @\exposid{parent_}@ = nullptr; // \expos - iterator_t @\exposid{current_}@ = iterator_t(); // \expos - iterator_t @\exposid{next_}@ = iterator_t(); // \expos - - constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, // \expos - iterator_t next); - - public: - using value_type = subrange>; - using difference_type = range_difference_t; - using iterator_category = input_iterator_tag; - using iterator_concept = @\seebelow@; - - @\exposid{iterator}@() = default; - - constexpr value_type operator*() const; - constexpr @\exposid{iterator}@& operator++(); - constexpr @\exposid{iterator}@ operator++(int); - - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; - - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); - friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); - }; -} -\end{codeblock} - -\pnum -\tcode{\exposid{iterator}::iterator_concept} is defined as follows: -\begin{itemize} -\item -If \tcode{V} models \libconcept{bidirectional_range}, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item -Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. -\end{itemize} +if (n > 0) { + ranges::advance(@\exposid{current_}@, @\exposid{stride_}@ * (n - 1)); + @\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{stride_}@, @\exposid{end_}@); +} else if (n < 0) { + ranges::advance(@\exposid{current_}@, @\exposid{stride_}@ * n + @\exposid{missing_}@); + @\exposid{missing_}@ = 0; +} +return *this; +\end{codeblock} +\end{itemdescr} +\indexlibrarymember{operator-=}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, iterator_t next); +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}, -\exposid{current_} with \tcode{current}, and -\exposid{next_} with \tcode{next}. +Equivalent to: \tcode{return *this += -x;} \end{itemdescr} +\indexlibrarymember{operator==}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr value_type operator*() const; +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\exposid{current_} is not equal to \exposid{next_}. - \pnum \returns -\tcode{subrange(\exposid{current_}, \exposid{next_})}. +\tcode{x.\exposid{current_} == x.\exposid{end_}}. \end{itemdescr} +\indexlibrarymember{operator==}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{equality_comparable}@>; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\exposid{current_} is not equal to \exposid{next_}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{current_}@ = @\exposid{next_}@; -@\exposid{next_}@ = @\exposid{parent_}@->@\exposid{find-next}@(@\exposid{current_}@); -return *this; -\end{codeblock} +\returns +\tcode{x.\exposid{current_} == y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator<}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; -++*this; -return tmp; -\end{codeblock} +\returns +\tcode{x.\exposid{current_} < y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator>}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; +friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -@\exposid{next_}@ = @\exposid{current_}@; -@\exposid{current_}@ = @\exposid{parent_}@->@\exposid{find-prev}@(@\exposid{next_}@); -return *this; -\end{codeblock} +Equivalent to: \tcode{return y < x;} \end{itemdescr} +\indexlibrarymember{operator<=}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; +friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; ---*this; -return tmp; -\end{codeblock} +Equivalent to: \tcode{return !(y < x);} \end{itemdescr} +\indexlibrarymember{operator>=}{stride_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} == y.\exposid{current_}}. +\effects +Equivalent to: \tcode{return !(x < y);} \end{itemdescr} +\indexlibrarymember{operator<=>}{stride_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{current_} == x.\exposid{next_}}. +\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. \end{itemdescr} -\rSec2[range.stride]{Stride view} - -\rSec3[range.stride.overview]{Overview} - -\pnum -\tcode{stride_view} presents a view of an underlying sequence, -advancing over $n$ elements at a time, -as opposed to the usual single-step succession. - -\pnum -The name \tcode{views::stride} denotes -a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{N}, -the expression \tcode{views::stride(E, N)} -is expression-equivalent to \tcode{stride_view(E, N)}. +\indexlibrarymember{operator+}{stride_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{example} +\effects +Equivalent to: \begin{codeblock} -auto input = views::iota(0, 12) | views::stride(3); -ranges::copy(input, ostream_iterator(cout, " ")); // prints \tcode{0 3 6 9} -ranges::copy(input | views::reverse, ostream_iterator(cout, " ")); // prints \tcode{9 6 3 0} +auto r = i; +r += n; +return r; \end{codeblock} -\end{example} +\end{itemdescr} -\rSec3[range.stride.view]{Class template \tcode{stride_view}} +\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V> - requires @\libconcept{view}@ - class stride_view : public view_interface> { - V @\exposid{base_}@; // \expos - range_difference_t @\exposid{stride_}@; // \expos - // \ref{range.stride.iterator}, class template \tcode{stride_view::\exposid{iterator}} - template class @\exposid{iterator}@; // \expos - public: - constexpr explicit stride_view(V base, range_difference_t stride); - - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } - - constexpr range_difference_t stride() const noexcept; - - constexpr auto begin() requires (!@\exposconcept{simple-view}@) { - return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); - } - - constexpr auto begin() const requires @\libconcept{range}@ { - return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); - } - - constexpr auto end() requires (!@\exposconcept{simple-view}@) { - if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@ && @\libconcept{forward_range}@) { - auto missing = (@\exposid{stride_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{stride_}@) % @\exposid{stride_}@; - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); - } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); - } else { - return default_sentinel; - } - } - - constexpr auto end() const requires @\libconcept{range}@ { - if constexpr (@\libconcept{common_range}@ && @\libconcept{sized_range}@ && @\libconcept{forward_range}@) { - auto missing = (@\exposid{stride_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{stride_}@) % @\exposid{stride_}@; - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@), missing); - } else if constexpr (@\libconcept{common_range}@ && !@\libconcept{bidirectional_range}@) { - return @\exposid{iterator}@(this, ranges::end(@\exposid{base_}@)); - } else { - return default_sentinel; - } - } - - constexpr auto size() requires @\libconcept{sized_range}@; - constexpr auto size() const requires @\libconcept{sized_range}@; - }; - - template - stride_view(R&&, range_difference_t) -> stride_view>; -} +auto r = i; +r -= n; +return r; \end{codeblock} +\end{itemdescr} -\indexlibraryctor{stride_view}% +\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr stride_view(V base, range_difference_t stride); +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{stride > 0} is \tcode{true}. - -\pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{stride_} with \tcode{stride}. +\returns +Let \tcode{N} be \tcode{(x.\exposid{current_} - y.\exposid{current_})}. +\begin{itemize} +\item +If \exposid{Base} models \libconcept{forward_range}, +\tcode{(N + x.\exposid{missing_} - y.\exposid{missing_}) / x.\exposid{stride_}}. +\item +Otherwise, if \tcode{N} is negative, \tcode{-\exposid{div-ceil}(-N, x.\exposid{stride_})}. +\item +Otherwise, \tcode{\exposid{div-ceil}(N, x.\exposid{stride_})}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{stride}{stride_view}% +\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr range_difference_t stride() const noexcept; +friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \returns -\exposid{stride_}. +\tcode{\exposid{div-ceil}(x.\exposid{end_} - x.\exposid{current_}, x.\exposid{stride_})}. \end{itemdescr} -\indexlibrarymember{size}{stride_view}% +\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr auto size() requires @\libconcept{sized_range}@; -constexpr auto size() const requires @\libconcept{sized_range}@; +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{stride_}@)); -\end{codeblock} +Equivalent to: \tcode{return -(y - x);} \end{itemdescr} -\rSec3[range.stride.iterator]{Class template \tcode{stride_view::\exposid{iterator}}} - -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V> - requires @\libconcept{view}@ - template - class stride_view::@\exposid{iterator}@ { - using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos +\indexlibrarymember{iter_move}{stride_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); +\end{itemdecl} - iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos - sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos - range_difference_t<@\exposid{Base}@> @\exposid{stride_}@ = 0; // \expos - range_difference_t<@\exposid{Base}@> @\exposid{missing_}@ = 0; // \expos +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} +\end{itemdescr} - constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, // \expos - range_difference_t<@\exposid{Base}@> missing = 0); - public: - using difference_type = range_difference_t<@\exposid{Base}@>; - using value_type = range_value_t<@\exposid{Base}@>; - using iterator_concept = @\seebelow@; - using iterator_category = @\seebelow@; // not always present +\indexlibrarymember{iter_swap}{stride_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) + requires @\libconcept{indirectly_swappable}@>; +\end{itemdecl} - @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_});} +\end{itemdescr} - constexpr @\exposid{iterator}@(@\exposid{iterator}@ other) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> - && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\rSec2[range.cartesian]{Cartesian product view} - constexpr iterator_t<@\exposid{Base}@> base() &&; - constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +\rSec3[range.cartesian.overview]{Overview} - constexpr decltype(auto) operator*() const { return *@\exposid{current_}@; } +\indexlibraryglobal{cartesian_product_view}% +\pnum +\tcode{cartesian_product_view} takes any non-zero number of ranges $n$ and +produces a view of tuples calculated by +the $n$-ary cartesian product of the provided ranges. - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; +\pnum +The name \tcode{views::cartesian_product} denotes a customization point object\iref{customization.point.object}. +Given a pack of subexpressions \tcode{Es}, +the expression \tcode{views::cartesian_product(Es...)} +is expression-equivalent to +\begin{itemize} +\item +\tcode{views::single(tuple())} +if \tcode{Es} is an empty pack, +\item +otherwise, +\tcode{cartesian_product_view...>(Es...)}. +\end{itemize} - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +\pnum +\begin{example} +\begin{codeblock} +vector v { 0, 1, 2 }; +for (auto&& [a, b, c] : views::cartesian_product(v, v, v)) { + cout << a << ' ' << b << ' ' << c << '\n'; +} +// The above prints +// \tcode{0 0 0} +// \tcode{0 0 1} +// \tcode{0 0 2} +// \tcode{0 1 0} +// \tcode{0 1 1} +// ... +\end{codeblock} +\end{example} - constexpr @\exposid{iterator}@& operator+=(difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@& operator-=(difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\rSec3[range.cartesian.view]{Class template \tcode{cartesian_product_view}} - constexpr decltype(auto) operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@> - { return *(*this + n); } +\indexlibraryglobal{cartesian_product_view}% +\begin{codeblock} +namespace std::ranges { + template + concept @\defexposconcept{cartesian-product-is-random-access}@ = // \expos + (@\libconcept{random_access_range}@<@\exposid{maybe-const}@> && ... && + (@\libconcept{random_access_range}@<@\exposid{maybe-const}@> + && @\libconcept{sized_range}@<@\exposid{maybe-const}@>)); - friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); + template + concept @\defexposconcept{cartesian-product-common-arg}@ = // \expos + @\libconcept{common_range}@ || (@\libconcept{sized_range}@ && @\libconcept{random_access_range}@); - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; + template + concept @\defexposconcept{cartesian-product-is-bidirectional}@ = // \expos + (@\libconcept{bidirectional_range}@<@\exposid{maybe-const}@> && ... && + (@\libconcept{bidirectional_range}@<@\exposid{maybe-const}@> + && @\exposconcept{cartesian-product-common-arg}@<@\exposid{maybe-const}@>)); - friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + template + concept @\defexposconcept{cartesian-product-is-common}@ = // \expos + @\exposconcept{cartesian-product-common-arg}@; - friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + template + concept @\defexposconcept{cartesian-product-is-sized}@ = // \expos + (@\libconcept{sized_range}@ && ...); - friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + template class FirstSent, class First, class... Vs> + concept @\defexposconcept{cartesian-is-sized-sentinel}@ = // \expos + (@\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ... + && (@\libconcept{sized_range}@<@\exposid{maybe-const}@> + && @\libconcept{sized_sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>>)); - friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + template<@\exposconcept{cartesian-product-common-arg}@ R> + constexpr auto @\exposid{cartesian-common-arg-end}@(R& r) { // \expos + if constexpr (@\libconcept{common_range}@) { + return ranges::end(r); + } else { + return ranges::begin(r) + ranges::distance(r); + } + } - friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; + template<@\libconcept{input_range}@ First, @\libconcept{forward_range}@... Vs> + requires (@\libconcept{view}@ && ... && @\libconcept{view}@) + class cartesian_product_view : public view_interface> { + private: + tuple @\exposid{bases_}@; // \expos + // \ref{range.cartesian.iterator}, class template \tcode{cartesian_product_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos - friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + public: + constexpr cartesian_product_view() = default; + constexpr explicit cartesian_product_view(First first_base, Vs... bases); - friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + constexpr @\exposid{iterator}@ begin() + requires (!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@); + constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{range}@ && ... && @\libconcept{range}@); - friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) - noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); + constexpr @\exposid{iterator}@ end() + requires ((!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@) && + @\exposconcept{cartesian-product-is-common}@); + constexpr @\exposid{iterator}@ end() const + requires @\exposconcept{cartesian-product-is-common}@; + constexpr default_sentinel_t end() const noexcept; - friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) - requires @\libconcept{indirectly_swappable}@>; + constexpr @\seebelow@ size() + requires @\exposconcept{cartesian-product-is-sized}@; + constexpr @\seebelow@ size() const + requires @\exposconcept{cartesian-product-is-sized}@; }; + + template + cartesian_product_view(Vs&&...) -> cartesian_product_view...>; } \end{codeblock} -\pnum -\tcode{\exposid{iterator}::iterator_concept} is defined as follows: -\begin{itemize} -\item -If \exposid{Base} models \libconcept{random_access_range}, -then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. -\item -Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item -Otherwise, if \exposid{Base} models \libconcept{forward_range}, -then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. -\item -Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. -\end{itemize} +\indexlibraryctor{cartesian_product_view}% +\begin{itemdecl} +constexpr explicit cartesian_product_view(First first_base, Vs... bases); +\end{itemdecl} +\begin{itemdescr} \pnum -The member \grammarterm{typedef-name} \tcode{iterator_category} is defined -if and only if \exposid{Base} models \libconcept{forward_range}. -In that case, -\tcode{\exposid{iterator}::iterator_category} is defined as follows: -\begin{itemize} -\item -Let \tcode{C} denote -the type \tcode{iterator_traits>::iterator_category}. -\item -If \tcode{C} models -\tcode{\libconcept{derived_from}}, -then \tcode{iterator_category} denotes \tcode{ran\-dom_access_iterator_tag}. -\item -Otherwise, \tcode{iterator_category} denotes \tcode{C}. -\end{itemize} +\effects +Initializes \exposid{bases_} +with \tcode{std::move(first_base), std::move(bases)...}. +\end{itemdescr} -\indexlibraryctor{stride_view::\exposid{iterator}}% +\indexlibrarymember{begin}{cartesian_product_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, - range_difference_t<@\exposid{Base}@> missing = 0); +constexpr @\exposid{iterator}@ begin() + requires (!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(current)}, -\exposid{end_} with \tcode{ranges::end(parent->\exposid{base_})}, -\exposid{stride_} with \tcode{parent->\exposid{stride_}}, and -\exposid{missing_} with \tcode{missing}. +Equivalent to: +\begin{codeblock} +return @\exposid{iterator}@(*this, @\exposid{tuple-transform}@(ranges::begin, @\exposid{bases_}@)); +\end{codeblock} \end{itemdescr} -\indexlibraryctor{stride_view::\exposid{iterator}}% +\indexlibrarymember{begin}{cartesian_product_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> - && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{range}@ && ... && @\libconcept{range}@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}, -\exposid{end_} with \tcode{std::move(i.\exposid{end_})}, -\exposid{stride_} with \tcode{i.\exposid{stride_}}, and -\exposid{missing_} with \tcode{i.\exposid{missing_}}. +Equivalent to: +\begin{codeblock} +return @\exposid{iterator}@(*this, @\exposid{tuple-transform}@(ranges::begin, @\exposid{bases_}@)); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{stride_view::\exposid{iterator}}% +\indexlibrarymember{end}{cartesian_product_view}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() &&; +constexpr @\exposid{iterator}@ end() + requires ((!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@) + && @\exposconcept{cartesian-product-is-common}@); +constexpr @\exposid{iterator}@ end() const + requires @\exposconcept{cartesian-product-is-common}@; \end{itemdecl} -\begin{itemdescr} +\begin{itemdescr} +\pnum +Let: +\begin{itemize} +\item +\exposid{is-const} be \tcode{true} for the const-qualified overload, and +\tcode{false} otherwise; +\item +\exposid{is-empty} be \tcode{true} +if the expression \tcode{ranges::empty(rng)} is \tcode{true} +for any \tcode{rng} among the underlying ranges except the first one and +\tcode{false} otherwise; and +\item +\tcode{\exposid{begin-or-first-end}(rng)} be expression-equivalent to +\tcode{\exposid{is-empty} ? ranges::begin(rng) : \brk{}\exposid{cartesian-common-arg-end}(rng)} +if \tcode{rng} is the first underlying range and +\tcode{ranges::begin(rng)} otherwise. +\end{itemize} + \pnum -\returns -\tcode{std::move(\exposid{current_})}. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{iterator}@<@\exposid{is-const}@> it(*this, @\exposid{tuple-transform}@( + [](auto& rng){ return @\exposid{begin-or-first-end}@(rng); }, @\exposid{bases_}@)); +return it; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{stride_view::\exposid{iterator}}% +\indexlibrarymember{end}{cartesian_product_view}% \begin{itemdecl} -constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +constexpr default_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\exposid{current_}. +\tcode{default_sentinel}. \end{itemdescr} -\indexlibrarymember{operator++}{stride_view::\exposid{iterator}}% +\indexlibrarymember{size}{cartesian_product_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +constexpr @\seebelow@ size() + requires @\exposconcept{cartesian-product-is-sized}@; +constexpr @\seebelow@ size() const + requires @\exposconcept{cartesian-product-is-sized}@; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. +The return type is an \impldef{return type of \tcode{cartesian_product_view::size}} unsigned-integer-like type. \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{stride_}@, @\exposid{end_}@); -return *this; -\end{codeblock} -\end{itemdescr} +\recommended +The return type should be the smallest unsigned-integer-like type +that is sufficiently wide to store the product of the maximum sizes of +all the underlying ranges, if such a type exists. -\indexlibrarymember{operator++}{stride_view::\exposid{iterator}}% -\begin{itemdecl} -constexpr void operator++(int); -\end{itemdecl} +\pnum +Let $p$ be the product of the sizes of all the ranges in \exposid{bases_}. -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{++*this;} +\expects +$p$ can be represented by the return type. + +\pnum +\returns +$p$. \end{itemdescr} -\indexlibrarymember{operator++}{stride_view::\exposid{iterator}}% -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; -\end{itemdecl} +\rSec3[range.cartesian.iterator]{Class template \tcode{cartesian_product_view::\exposid{iterator}}} -\begin{itemdescr} -\pnum -\effects -Equivalent to: +\indexlibraryglobal{cartesian_product_view::\exposid{iterator}}% \begin{codeblock} -auto tmp = *this; -++*this; -return tmp; +namespace std::ranges { + template<@\libconcept{input_range}@ First, @\libconcept{forward_range}@... Vs> + requires (@\libconcept{view}@ && ... && @\libconcept{view}@) + template + class cartesian_product_view::@\exposid{iterator}@ { + public: + using iterator_category = input_iterator_tag; + using iterator_concept = @\seebelow@; + using value_type = tuple>, + range_value_t<@\exposid{maybe-const}@>...>; + using reference = tuple>, + range_reference_t<@\exposid{maybe-const}@>...>; + using difference_type = @\seebelow@; + + @\exposid{iterator}@() = default; + + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && + (@\libconcept{convertible_to}@, iterator_t> && + ... && @\libconcept{convertible_to}@, iterator_t>); + + constexpr auto operator*() const; + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{maybe-const}@>; + + constexpr @\exposid{iterator}@& operator--() + requires @\exposconcept{cartesian-product-is-bidirectional}@; + constexpr @\exposid{iterator}@ operator--(int) + requires @\exposconcept{cartesian-product-is-bidirectional}@; + + constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\exposconcept{cartesian-product-is-random-access}@; + constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\exposconcept{cartesian-product-is-random-access}@; + + constexpr reference operator[](difference_type n) const + requires @\exposconcept{cartesian-product-is-random-access}@; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{equality_comparable}@>>; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); + + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; + + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + requires @\exposconcept{cartesian-product-is-random-access}@; + friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) + requires @\exposconcept{cartesian-product-is-random-access}@; + friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) + requires @\exposconcept{cartesian-product-is-random-access}@; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{cartesian-is-sized-sentinel}@; + + friend constexpr difference_type operator-(const @\exposid{iterator}@& i, default_sentinel_t) + requires @\exposconcept{cartesian-is-sized-sentinel}@; + friend constexpr difference_type operator-(default_sentinel_t, const @\exposid{iterator}@& i) + requires @\exposconcept{cartesian-is-sized-sentinel}@; + + friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); + + friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires (@\libconcept{indirectly_swappable}@>> && ... && + @\libconcept{indirectly_swappable}@>>); + + private: + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + @\exposidnc{Parent}@* @\exposidnc{parent_}@ = nullptr; // \expos + tuple>, + iterator_t<@\exposidnc{maybe-const}@>...> @\exposidnc{current_}@; // \expos + + template + constexpr void @\exposidnc{next}@(); // \expos + + template + constexpr void @\exposidnc{prev}@(); // \expos + + template + constexpr difference_type @\exposidnc{distance-from}@(const Tuple& t) const; // \expos + + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, tuple>, + iterator_t<@\exposidnc{maybe-const}@>...> current); // \expos + }; +} \end{codeblock} -\end{itemdescr} -\indexlibrarymember{operator--}{stride_view::\exposid{iterator}}% -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; -\end{itemdecl} +\pnum +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +\begin{itemize} +\item +If \tcode{\exposconcept{cartesian-product-is-random-access}} +is modeled, +then \tcode{iterator_con\-cept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, +if \tcode{\exposconcept{cartesian-product-is-bidirectional}} +is modeled, +then \tcode{it\-erator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, +if \tcode{\exposid{maybe-const}} models \libconcept{forward_range}, +then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -ranges::advance(@\exposid{current_}@, @\exposid{missing_}@ - @\exposid{stride_}@); -@\exposid{missing_}@ = 0; -return *this; -\end{codeblock} -\end{itemdescr} +\tcode{\exposid{iterator}::difference_type} is +an \impldef{type of \tcode{ranges::cartesian_product_view::\exposid{iterator}::difference_type}} +signed-integer-like type. + +\pnum +\recommended +\tcode{\exposid{iterator}::difference_type} should be +the smallest signed-integer-like type +that is sufficiently wide to store +the product of the maximum sizes of all underlying ranges +if such a type exists. -\indexlibrarymember{operator--}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +template + constexpr void @\exposid{next}@(); \end{itemdecl} \begin{itemdescr} @@ -14683,143 +16839,158 @@ \effects Equivalent to: \begin{codeblock} -auto tmp = *this; ---*this; -return tmp; +auto& it = std::get(@\exposid{current_}@); +++it; +if constexpr (N > 0) { + if (it == ranges::end(std::get(@\exposid{parent_}@->@\exposid{bases_}@))) { + it = ranges::begin(std::get(@\exposid{parent_}@->@\exposid{bases_}@)); + @\exposid{next}@(); + } +} \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+=}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +template + constexpr void @\exposid{prev}@(); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -If \tcode{n} is positive, -\tcode{ranges::distance(\exposid{current_}, \exposid{end_}) > \exposid{stride_} * (n - 1)} -is \tcode{true}. -\begin{note} -If \tcode{n} is negative, the \Fundescx{Effects} paragraph implies a precondition. -\end{note} - \pnum \effects Equivalent to: \begin{codeblock} -if (n > 0) { - ranges::advance(@\exposid{current_}@, @\exposid{stride_}@ * (n - 1)); - @\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{stride_}@, @\exposid{end_}@); -} else if (n < 0) { - ranges::advance(@\exposid{current_}@, @\exposid{stride_}@ * n + @\exposid{missing_}@); - @\exposid{missing_}@ = 0; +auto& it = std::get(@\exposid{current_}@); +if constexpr (N > 0) { + if (it == ranges::begin(std::get(@\exposid{parent_}@->@\exposid{bases_}@))) { + it = @\exposid{cartesian-common-arg-end}@(std::get(@\exposid{parent_}@->@\exposid{bases_}@)); + @\exposid{prev}@(); + } } -return *this; +--it; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator-=}{stride_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +template + constexpr difference_type @\exposid{distance-from}@(const Tuple& t) const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return *this += -x;} -\end{itemdescr} +Let: +\begin{itemize} +\item +$\exposid{scaled-size}(N)$ be the product of +\tcode{static_cast(ranges::size(std::get<\brk{}$N$>(\exposid{parent_}->\exposid{bases_})))} and +$\exposid{scaled-size}(N+1)$ +if $N \le \tcode{sizeof...(Vs)}$, otherwise \tcode{static_cast(1)}; +\item +$\exposid{scaled-distance}(N)$ be the product of +\tcode{static_cast(std::get<$N$>(\exposid{cur\-rent_}) - std::get<$N$>(t))} and $\exposid{scaled-size}(N+1)$; and +\item +\exposid{scaled-sum} be the sum of $\exposid{scaled-distance}(N)$ +for every integer $0 \le N \le \tcode{sizeof...(Vs)}$. +\end{itemize} -\indexlibrarymember{operator==}{stride_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); -\end{itemdecl} +\pnum +\expects +\exposid{scaled-sum} can be represented by \tcode{difference_type}. -\begin{itemdescr} \pnum \returns -\tcode{x.\exposid{current_} == x.\exposid{end_}}. +\exposid{scaled-sum}. \end{itemdescr} -\indexlibrarymember{operator==}{stride_view::\exposid{iterator}}% +\indexlibraryctor{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, tuple>, + iterator_t<@\exposid{maybe-const}@>...> current); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} == y.\exposid{current_}}. +\effects +Initializes +\exposid{parent_} with \tcode{addressof(parent)} and +\exposid{current_} with \tcode{std::move(current)}. \end{itemdescr} -\indexlibrarymember{operator<}{stride_view::\exposid{iterator}}% +\indexlibraryctor{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && + (@\libconcept{convertible_to}@, iterator_t> && + ... && @\libconcept{convertible_to}@, iterator_t>); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} < y.\exposid{current_}}. +\effects +Initializes +\exposid{parent_} with \tcode{i.\exposid{parent_}} and +\exposid{current_} with \tcode{std::move(i.\exposid{current_})}. \end{itemdescr} -\indexlibrarymember{operator>}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator*}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr auto operator*() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return y < x;} +Equivalent to: +\begin{codeblock} +return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator<=}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator++}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(y < x);} +Equivalent to: +\begin{codeblock} +@\exposid{next}@(); +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator>=}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator++}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(x < y);} +Equivalent to \tcode{++*this}. \end{itemdescr} -\indexlibrarymember{operator<=>}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator++}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{maybe-const}@>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator--}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr @\exposid{iterator}@ operator+(difference_type n, const @\exposid{iterator}@& i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator--() + requires @\exposconcept{cartesian-product-is-bidirectional}@; \end{itemdecl} \begin{itemdescr} @@ -14827,16 +16998,15 @@ \effects Equivalent to: \begin{codeblock} -auto r = i; -r += n; -return r; +@\exposid{prev}@(); +return *this; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator--}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator--(int) + requires @\exposconcept{cartesian-product-is-bidirectional}@; \end{itemdecl} \begin{itemdescr} @@ -14844,446 +17014,459 @@ \effects Equivalent to: \begin{codeblock} -auto r = i; -r -= n; -return r; +auto tmp = *this; +--*this; +return tmp; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator+=}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum -\returns -Let \tcode{N} be \tcode{(x.\exposid{current_} - y.\exposid{current_})}. +Let \tcode{orig} be the value of \tcode{*this} before the call. + +Let \tcode{ret} be: \begin{itemize} \item -If \exposid{Base} models \libconcept{forward_range}, -\tcode{(N + x.\exposid{missing_} - y.\exposid{missing_}) / x.\exposid{stride_}}. +If \tcode{x > 0}, +the value of \tcode{*this} had \exposid{next} been called \tcode{x} times. \item -Otherwise, if \tcode{N} is negative, \tcode{-\exposid{div-ceil}(-N, x.\exposid{stride_})}. +Otherwise, if \tcode{x < 0}, +the value of \tcode{*this} had \exposid{prev} been called \tcode{-x} times. \item -Otherwise, \tcode{\exposid{div-ceil}(N, x.\exposid{stride_})}. +Otherwise, \tcode{orig}. \end{itemize} -\end{itemdescr} -\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% -\begin{itemdecl} -friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; -\end{itemdecl} +\pnum +\expects +\tcode{x} is in the range +$[\tcode{ranges::distance(*this, ranges::begin(*\exposid{parent_}))},$\newline +$\tcode{ranges::distance(*this, ranges::end(*\exposid{parent_}))}]$. + +\pnum +\effects +Sets the value of \tcode{*this} to \tcode{ret}. -\begin{itemdescr} \pnum \returns -\tcode{\exposid{div-ceil}(x.\exposid{end_} - x.\exposid{current_}, x.\exposid{stride_})}. +\tcode{*this}. + +\pnum +\complexity +Constant. \end{itemdescr} -\indexlibrarymember{operator-}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator-=}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, default_sentinel_t y) - requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return -(y - x);} +Equivalent to: +\begin{codeblock} +*this += -x; +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{iter_move}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator[]}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) - noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); +constexpr reference operator[](difference_type n) const + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} +Equivalent to: \tcode{return *((*this) + n);} \end{itemdescr} -\indexlibrarymember{iter_swap}{stride_view::\exposid{iterator}}% +\indexlibrarymember{operator==}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) - requires @\libconcept{indirectly_swappable}@>; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{equality_comparable}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_});} +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} \end{itemdescr} -\rSec2[range.cartesian]{Cartesian product view} - -\rSec3[range.cartesian.overview]{Overview} - -\indexlibraryglobal{cartesian_product_view}% -\pnum -\tcode{cartesian_product_view} takes any non-zero number of ranges $n$ and -produces a view of tuples calculated by -the $n$-ary cartesian product of the provided ranges. - -\pnum -The name \tcode{views::cartesian_product} denotes a customization point object\iref{customization.point.object}. -Given a pack of subexpressions \tcode{Es}, -the expression \tcode{views::cartesian_product(Es...)} -is expression-equivalent to -\begin{itemize} -\item -\tcode{views::single(tuple())} -if \tcode{Es} is an empty pack, -\item -otherwise, -\tcode{cartesian_product_view...>(Es...)}. -\end{itemize} - -\pnum -\begin{example} -\begin{codeblock} -vector v { 0, 1, 2 }; -for (auto&& [a, b, c] : views::cartesian_product(v, v, v)) { - cout << a << ' ' << b << ' ' << c << '\n'; -} -// The above prints -// \tcode{0 0 0} -// \tcode{0 0 1} -// \tcode{0 0 2} -// \tcode{0 1 0} -// \tcode{0 1 1} -// ... -\end{codeblock} -\end{example} - -\rSec3[range.cartesian.view]{Class template \tcode{cartesian_product_view}} - -\begin{codeblock} -namespace std::ranges { - template - concept @\defexposconcept{cartesian-product-is-random-access}@ = // \expos - (@\libconcept{random_access_range}@<@\exposid{maybe-const}@> && ... && - (@\libconcept{random_access_range}@<@\exposid{maybe-const}@> - && @\libconcept{sized_range}@<@\exposid{maybe-const}@>)); - - template - concept @\defexposconcept{cartesian-product-common-arg}@ = // \expos - @\libconcept{common_range}@ || (@\libconcept{sized_range}@ && @\libconcept{random_access_range}@); - - template - concept @\defexposconcept{cartesian-product-is-bidirectional}@ = // \expos - (@\libconcept{bidirectional_range}@<@\exposid{maybe-const}@> && ... && - (@\libconcept{bidirectional_range}@<@\exposid{maybe-const}@> - && @\exposconcept{cartesian-product-common-arg}@<@\exposid{maybe-const}@>)); - - template - concept @\defexposconcept{cartesian-product-is-common}@ = // \expos - @\exposconcept{cartesian-product-common-arg}@; - - template - concept @\defexposconcept{cartesian-product-is-sized}@ = // \expos - (@\libconcept{sized_range}@ && ...); - - template class FirstSent, class First, class... Vs> - concept @\defexposconcept{cartesian-is-sized-sentinel}@ = // \expos - (@\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>> && ... - && (@\libconcept{sized_range}@<@\exposid{maybe-const}@> - && @\libconcept{sized_sentinel_for}@>, - iterator_t<@\exposid{maybe-const}@>>)); - - template<@\exposconcept{cartesian-product-common-arg}@ R> - constexpr auto @\exposid{cartesian-common-arg-end}@(R& r) { // \expos - if constexpr (@\libconcept{common_range}@) { - return ranges::end(r); - } else { - return ranges::begin(r) + ranges::distance(r); - } - } - - template<@\libconcept{input_range}@ First, @\libconcept{forward_range}@... Vs> - requires (@\libconcept{view}@ && ... && @\libconcept{view}@) - class cartesian_product_view : public view_interface> { - private: - tuple @\exposid{bases_}@; // \expos - // \ref{range.cartesian.iterator}, class template \tcode{cartesian_product_view::\exposid{iterator}} - template class @\exposid{iterator}@; // \expos - - public: - constexpr cartesian_product_view() = default; - constexpr explicit cartesian_product_view(First first_base, Vs... bases); +\indexlibrarymember{operator==}{cartesian_product_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +\end{itemdecl} - constexpr @\exposid{iterator}@ begin() - requires (!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@); - constexpr @\exposid{iterator}@ begin() const - requires (@\libconcept{range}@ && ... && @\libconcept{range}@); +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{std::get<$i$>(x.\exposid{current_}) == ranges::end(std::get<$i$>(x.\exposid{parent_}->\exposid{bases_}))} +is \tcode{true} +for any integer $0 \le i \le \tcode{sizeof...(Vs)}$; +otherwise, \tcode{false}. +\end{itemdescr} - constexpr @\exposid{iterator}@ end() - requires ((!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@) && - @\exposconcept{cartesian-product-is-common}@); - constexpr @\exposid{iterator}@ end() const - requires @\exposconcept{cartesian-product-is-common}@; - constexpr default_sentinel_t end() const noexcept; +\indexlibrarymember{operator<=>}{cartesian_product_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; +\end{itemdecl} - constexpr @\seebelow@ size() - requires @\exposconcept{cartesian-product-is-sized}@; - constexpr @\seebelow@ size() const - requires @\exposconcept{cartesian-product-is-sized}@; - }; +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};} +\end{itemdescr} - template - cartesian_product_view(Vs&&...) -> cartesian_product_view...>; -} -\end{codeblock} +\indexlibrarymember{operator+}{cartesian_product_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + requires @\exposconcept{cartesian-product-is-random-access}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}(x) += y;} +\end{itemdescr} +\indexlibrarymember{operator+}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -constexpr explicit cartesian_product_view(First first_base, Vs... bases); +friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{bases_} -with \tcode{std::move(first_base), std::move(bases)...}. +Equivalent to: \tcode{return y + x;} \end{itemdescr} +\indexlibrarymember{operator-}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ begin() - requires (!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@); +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return @\exposid{iterator}@(*this, @\exposid{tuple-transform}@(ranges::begin, @\exposid{bases_}@)); -\end{codeblock} +Equivalent to: \tcode{return \exposid{iterator}(x) -= y;} \end{itemdescr} +\indexlibrarymember{operator-}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ begin() const - requires (@\libconcept{range}@ && ... && @\libconcept{range}@); +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{cartesian-is-sized-sentinel}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return @\exposid{iterator}@(*this, @\exposid{tuple-transform}@(ranges::begin, @\exposid{bases_}@)); -\end{codeblock} +Equivalent to: \tcode{return x.\exposid{distance-from}(y.\exposid{current_});} \end{itemdescr} +\indexlibrarymember{operator-}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ end() - requires ((!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@) - && @\exposconcept{cartesian-product-is-common}@); -constexpr @\exposid{iterator}@ end() const - requires @\exposconcept{cartesian-product-is-common}@; +friend constexpr difference_type operator-(const @\exposid{iterator}@& i, default_sentinel_t) + requires @\exposconcept{cartesian-is-sized-sentinel}@; \end{itemdecl} \begin{itemdescr} \pnum -Let: +Let \exposid{end-tuple} be an object of a type +that is a specialization of \tcode{tuple}, such that: \begin{itemize} \item -\exposid{is-const} be \tcode{true} for the const-qualified overload, and -\tcode{false} otherwise; -\item -\exposid{is-empty} be \tcode{true} -if the expression \tcode{ranges::empty(rng)} is \tcode{true} -for any \tcode{rng} among the underlying ranges except the first one and -\tcode{false} otherwise; and +\tcode{std::get<0>(\exposid{end-tuple})} has the same value as +\tcode{ranges::end(std::get<0>(i.\exposid{parent_}->\exposid{ba\-ses_}))}; \item -\tcode{\exposid{begin-or-first-end}(rng)} be expression-equivalent to -\tcode{\exposid{is-empty} ? ranges::begin(rng) : \brk{}\exposid{cartesian-common-arg-end}(rng)} -if \tcode{rng} is the first underlying range and -\tcode{ranges::begin(rng)} otherwise. +\tcode{std::get<$N$>(\exposid{end-tuple})} has the same value as +\tcode{ranges::begin(std::get<$N$>(i.\exposid{parent_}->\exposid{bases_}))} +for every integer $1 \le N \le \tcode{sizeof...(Vs)}$. \end{itemize} \pnum \effects -Equivalent to: -\begin{codeblock} -@\exposid{iterator}@<@\exposid{is-const}@> it(*this, @\exposid{tuple-transform}@( - [](auto& rng){ return @\exposid{begin-or-first-end}@(rng); }, @\exposid{bases_}@)); -return it; -\end{codeblock} +Equivalent to: \tcode{return i.\exposid{distance-from}(\exposid{end-tuple});} \end{itemdescr} +\indexlibrarymember{operator-}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -constexpr default_sentinel_t end() const noexcept; +friend constexpr difference_type operator-(default_sentinel_t s, const @\exposid{iterator}@& i) + requires @\exposconcept{cartesian-is-sized-sentinel}@; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{default_sentinel}. +\effects +Equivalent to: \tcode{return -(i - s);} \end{itemdescr} +\indexlibrarymember{iter_move}{cartesian_product_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\seebelow@ size() - requires @\exposconcept{cartesian-product-is-sized}@; -constexpr @\seebelow@ size() const - requires @\exposconcept{cartesian-product-is-sized}@; +friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum -The return type is an \impldef{return type of \tcode{cartesian_product_view::size}} unsigned-integer-like type. +\effects +Equivalent to: \tcode{return \exposid{tuple-transform}(ranges::iter_move, i.\exposid{current_});} \pnum -\recommended -The return type should be the smallest unsigned-integer-like type -that is sufficiently wide to store the product of the maximum sizes of -all the underlying ranges, if such a type exists. +\remarks +The exception specification is equivalent to +the logical \logop{and} of the following expressions: +\begin{itemize} +\item +\tcode{noexcept(ranges::iter_move(std::get<$N$>(i.\exposid{current_})))} +for every integer\newline $0 \le N \le \tcode{sizeof...(Vs)}$, +\item +\tcode{is_nothrow_move_constructible_v>>}\newline +for every type \tcode{T} in \tcode{First, Vs...}. +\end{itemize} +\end{itemdescr} -\pnum -Let $p$ be the product of the sizes of all the ranges in \exposid{bases_}. +\indexlibrarymember{iter_swap}{cartesian_product_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires (@\libconcept{indirectly_swappable}@>> && ... && + @\libconcept{indirectly_swappable}@>>); +\end{itemdecl} +\begin{itemdescr} \pnum -\expects -$p$ can be represented by the return type. +\effects +For every integer $0 \le i \le \tcode{sizeof...(Vs)}$, performs: +\begin{codeblock} +ranges::iter_swap(std::get<@$i$@>(l.@\exposid{current_}@), std::get<@$i$@>(r.@\exposid{current_}@)) +\end{codeblock} \pnum -\returns -$p$. +\remarks +The exception specification is equivalent to the logical \logop{and} of the following expressions: +\begin{itemize} +\item +\tcode{noexcept(ranges::iter_swap(std::get<$i$>(l.\exposid{current_}), std::get<$i$>(r.\exposid{current_})))} +for\newline every integer $0 \le i \le \tcode{sizeof...(Vs)}$. +\end{itemize} \end{itemdescr} -\rSec3[range.cartesian.iterator]{Class template \tcode{cartesian_product_view::\exposid{iterator}}} +\rSec2[range.cache.latest]{Cache latest view} + +\rSec3[range.cache.latest.overview]{Overview} + +\pnum +\tcode{cache_latest_view} caches the last-accessed element of +its underlying sequence +so that the element does not have to be recomputed on repeated access. +\begin{note} +This is useful if computation of the element to produce is expensive. +\end{note} + +\pnum +The name \tcode{views::cache_latest} denotes +a range adaptor object\iref{range.adaptor.object}. +Let \tcode{E} be an expression. +The expression \tcode{views::cache_latest(E)} is expression-equivalent to +\tcode{cache_latest_view(E)}. + +\rSec3[range.cache.latest.view]{Class template \tcode{cache_latest_view}} \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ First, @\libconcept{forward_range}@... Vs> - requires (@\libconcept{view}@ && ... && @\libconcept{view}@) - template - class cartesian_product_view::@\exposid{iterator}@ { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class @\libglobal{cache_latest_view}@ : public view_interface> { + V @\exposid{base_}@ = V(); // \expos + using @\exposid{cache-t}@ = conditional_t>, // \expos + add_pointer_t>, + range_reference_t>; + + @\exposid{non-propagating-cache}@<@\exposid{cache-t}@> @\exposid{cache_}@; // \expos + + // \ref{range.cache.latest.iterator}, class \tcode{cache_latest_view::\exposid{iterator}} + class @\exposid{iterator}@; // \expos + // \ref{range.cache.latest.sentinel}, class \tcode{cache_latest_view::\exposid{sentinel}} + class @\exposid{sentinel}@; // \expos + public: - using iterator_category = input_iterator_tag; - using iterator_concept = @\seebelow@; - using value_type = tuple>, - range_value_t<@\exposid{maybe-const}@>...>; - using reference = tuple>, - range_reference_t<@\exposid{maybe-const}@>...>; - using difference_type = @\seebelow@; + cache_latest_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit cache_latest_view(V base); - @\exposid{iterator}@() = default; + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && - (@\libconcept{convertible_to}@, iterator_t> && - ... && @\libconcept{convertible_to}@, iterator_t>); + constexpr auto begin(); + constexpr auto end(); - constexpr auto operator*() const; - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{maybe-const}@>; + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; + }; - constexpr @\exposid{iterator}@& operator--() - requires @\exposconcept{cartesian-product-is-bidirectional}@; - constexpr @\exposid{iterator}@ operator--(int) - requires @\exposconcept{cartesian-product-is-bidirectional}@; + template + cache_latest_view(R&&) -> cache_latest_view>; +} +\end{codeblock} - constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\exposconcept{cartesian-product-is-random-access}@; - constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\exposconcept{cartesian-product-is-random-access}@; +\indexlibraryctor{cache_latest_view}% +\begin{itemdecl} +constexpr explicit cache_latest_view(V base); +\end{itemdecl} - constexpr reference operator[](difference_type n) const - requires @\exposconcept{cartesian-product-is-random-access}@; +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}. +\end{itemdescr} - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>>; +\indexlibrarymember{begin}{cache_latest_view}% +\begin{itemdecl} +constexpr auto begin(); +\end{itemdecl} - friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}(*this);} +\end{itemdescr} - friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; +\indexlibrarymember{end}{cache_latest_view}% +\begin{itemdecl} +constexpr auto end(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{sentinel}(*this);} +\end{itemdescr} + +\indexlibrarymember{size}{cache_latest_view}% +\begin{itemdecl} +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return ranges::size(\exposid{base_});} +\end{itemdescr} + +\rSec3[range.cache.latest.iterator]{Class \tcode{cache_latest_view::\exposid{iterator}}} - friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) - requires @\exposconcept{cartesian-product-is-random-access}@; - friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) - requires @\exposconcept{cartesian-product-is-random-access}@; - friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) - requires @\exposconcept{cartesian-product-is-random-access}@; - friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{cartesian-is-sized-sentinel}@; +\indexlibraryglobal{cache_latest_view::\exposid{iiterator}}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class cache_latest_view::@\exposid{iterator}@ { + cache_latest_view* @\exposid{parent_}@; // \expos + iterator_t @\exposid{current_}@; // \expos - friend constexpr difference_type operator-(const @\exposid{iterator}@& i, default_sentinel_t) - requires @\exposconcept{cartesian-is-sized-sentinel}@; - friend constexpr difference_type operator-(default_sentinel_t, const @\exposid{iterator}@& i) - requires @\exposconcept{cartesian-is-sized-sentinel}@; + constexpr explicit @\exposid{iterator}@(cache_latest_view& parent); // \expos - friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); + public: + using difference_type = range_difference_t; + using value_type = range_value_t; + using iterator_concept = input_iterator_tag; - friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) - requires (@\libconcept{indirectly_swappable}@>> && ... && - @\libconcept{indirectly_swappable}@>>); + @\exposid{iterator}@(@\exposid{iterator}@&&) = default; + @\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default; - private: - using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos - @\exposidnc{Parent}@* @\exposidnc{parent_}@ = nullptr; // \expos - tuple>, - iterator_t<@\exposidnc{maybe-const}@>...> @\exposidnc{current_}@; // \expos + constexpr iterator_t base() &&; + constexpr const iterator_t& base() const & noexcept; - template - constexpr void @\exposidnc{next}@(); // \expos + constexpr range_reference_t& operator*() const; - template - constexpr void @\exposidnc{prev}@(); // \expos + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); - template - constexpr difference_type @\exposidnc{distance-from}@(const Tuple& t) const; // \expos + friend constexpr range_rvalue_reference_t iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, tuple>, - iterator_t<@\exposidnc{maybe-const}@>...> current); // \expos + friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) + requires @\libconcept{indirectly_swappable}@>; }; } \end{codeblock} +\indexlibraryctor{cache_latest_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr explicit @\exposid{iterator}@(cache_latest_view& parent); +\end{itemdecl} + +\begin{itemdescr} \pnum -\tcode{\exposid{iterator}::iterator_concept} is defined as follows: -\begin{itemize} -\item -If \tcode{\exposconcept{cartesian-product-is-random-access}} -is modeled, -then \tcode{iterator_con\-cept} denotes \tcode{random_access_iterator_tag}. -\item -Otherwise, -if \tcode{\exposconcept{cartesian-product-is-bidirectional}} -is modeled, -then \tcode{it\-erator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item -Otherwise, -if \tcode{\exposid{maybe-const}} models \libconcept{forward_range}, -then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. -\item -Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. -\end{itemize} +\effects +Initializes \exposid{current_} with +\tcode{ranges::begin(parent.\exposid{base_})} +and \exposid{parent_} with \tcode{addressof(par\-ent)}. +\end{itemdescr} +\indexlibrarymember{base}{cache_latest_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr iterator_t base() &&; +\end{itemdecl} + +\begin{itemdescr} \pnum -\tcode{\exposid{iterator}::difference_type} is -an \impldef{type of \tcode{ranges::cartesian_product_view::\exposid{iterator}::difference_type}} -signed-integer-like type. +\returns +\tcode{std::move(\exposid{current_})}. +\end{itemdescr} + +\indexlibrarymember{base}{cache_latest_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr const iterator_t& base() const & noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\recommended -\tcode{\exposid{iterator}::difference_type} should be -the smallest signed-integer-like type -that is sufficiently wide to store -the product of the maximum sizes of all underlying ranges -if such a type exists. +\returns +\exposid{current_}. +\end{itemdescr} + +\indexlibrarymember{operator++}{cache_latest_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} +\begin{itemdescr} \pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{parent_}@->@\exposid{cache_}@.reset(); +++@\exposid{current_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} -template - constexpr void @\exposid{next}@(); +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{++*this}. +\end{itemdescr} + +\indexlibrarymember{operator*}{cache_latest_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr range_reference_t& operator*() const; \end{itemdecl} \begin{itemdescr} @@ -15291,404 +17474,421 @@ \effects Equivalent to: \begin{codeblock} -auto& it = std::get(@\exposid{current_}@); -++it; -if constexpr (N > 0) { - if (it == ranges::end(std::get(@\exposid{parent_}@->@\exposid{bases_}@))) { - it = ranges::begin(std::get(@\exposid{parent_}@->@\exposid{bases_}@)); - @\exposid{next}@(); +if constexpr (is_reference_v>) { + if (!@\exposid{parent_}@->@\exposid{cache_}@) { + @\exposid{parent_}@->@\exposid{cache_}@ = addressof(@\exposid{as-lvalue}@(*@\exposid{current_}@)); } + return **@\exposid{parent_}@->@\exposid{cache_}@; +} else { + if (!@\exposid{parent_}@->c@\exposid{ache_}@) { + @\exposid{parent_}@->@\exposid{cache_}@.@\exposid{emplace-deref}@(@\exposid{current_}@); + } + return *@\exposid{parent_}@->@\exposid{cache_}@; } \end{codeblock} +\begin{note} +Evaluations of \tcode{operator*} on the same iterator object +can conflict\iref{intro.races}. +\end{note} \end{itemdescr} +\indexlibrarymember{iter_move}{cache_latest_view::\exposid{iterator}}% \begin{itemdecl} -template - constexpr void @\exposid{prev}@(); +friend constexpr range_rvalue_reference_t iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: +Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{iter_swap}{cache_latest_view::\exposid{iterator}}% +\begin{itemdecl} +friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) + requires @\libconcept{indirectly_swappable}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to +\tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_})}. +\end{itemdescr} + +\rSec3[range.cache.latest.sentinel]{Class \tcode{cache_latest_view::\exposid{sentinel}}} + +\indexlibraryglobal{cache_latest_view::\exposid{sentinel}}% \begin{codeblock} -auto& it = std::get(@\exposid{current_}@); -if constexpr (N > 0) { - if (it == ranges::begin(std::get(@\exposid{parent_}@->@\exposid{bases_}@))) { - it = @\exposid{cartesian-common-arg-end}@(std::get(@\exposid{parent_}@->@\exposid{bases_}@)); - @\exposid{prev}@(); - } +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class cache_latest_view::@\exposid{sentinel}@ { + sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos + + constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent); // \expos + + public: + @\exposid{sentinel}@() = default; + + constexpr sentinel_t base() const; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + + friend constexpr range_difference_t operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + friend constexpr range_difference_t operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; + }; } ---it; \end{codeblock} + +\indexlibraryctor{cache_latest_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(cache_latest_view& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. \end{itemdescr} +\indexlibrarymember{base}{cache_latest_view::\exposid{sentinel}}% \begin{itemdecl} -template - constexpr difference_type @\exposid{distance-from}@(const Tuple& t) const; +constexpr sentinel_t base() const; \end{itemdecl} \begin{itemdescr} \pnum -Let: -\begin{itemize} -\item -$\exposid{scaled-size}(N)$ be the product of -\tcode{static_cast(ranges::size(std::get<\brk{}$N$>(\exposid{parent_}->\exposid{bases_})))} and -$\exposid{scaled-size}(N+1)$ -if $N \le \tcode{sizeof...(Vs)}$, otherwise \tcode{static_cast(1)}; -\item -$\exposid{scaled-distance}(N)$ be the product of -\tcode{static_cast(std::get<$N$>(\exposid{cur\-rent_}) - std::get<$N$>(t))} and $\exposid{scaled-size}(N+1)$; and -\item -\exposid{scaled-sum} be the sum of $\exposid{scaled-distance}(N)$ -for every integer $0 \le N \le \tcode{sizeof...(Vs)}$. -\end{itemize} +\returns +\exposid{end_}. +\end{itemdescr} + +\indexlibrarymember{operator==}{cache_latest_view::\exposid{iterator}}% +\indexlibrarymember{operator==}{cache_latest_view::\exposid{sentinel}}% +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +\end{itemdecl} +\begin{itemdescr} \pnum -\expects -\exposid{scaled-sum} can be represented by \tcode{difference_type}. +\returns +\tcode{x.\exposid{current_} == y.\exposid{end_}}. +\end{itemdescr} + +\indexlibrarymember{operator-}{cache_latest_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{cache_latest_view::\exposid{sentinel}}% +\begin{itemdecl} +friend constexpr range_difference_t operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; +\end{itemdecl} +\begin{itemdescr} \pnum \returns -\exposid{scaled-sum}. +\tcode{x.\exposid{current_} - y.\exposid{end_}}. \end{itemdescr} +\indexlibrarymember{operator-}{cache_latest_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{cache_latest_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, tuple>, - iterator_t<@\exposid{maybe-const}@>...> current); +friend constexpr range_difference_t operator-(const @\exposid{sentinel}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes -\exposid{parent_} with \tcode{addressof(parent)} and -\exposid{current_} with \tcode{std::move(current)}. +\returns +\tcode{x.\exposid{end_} - y.\exposid{current_}}. \end{itemdescr} +\rSec2[range.to.input]{To input view} + +\rSec3[range.to.input.overview]{Overview} + +\pnum +\tcode{to_input_view} presents a view of an underlying sequence +as an input-only non-common range. +\begin{note} +This is useful to avoid overhead +that can be necessary to provide support for the operations +needed for greater iterator strength. +\end{note} + +\pnum +The name \tcode{views::to_input} denotes +a range adaptor object\iref{range.adaptor.object}. +Let \tcode{E} be an expression and let \tcode{T} be \tcode{decltype((E))}. +The expression \tcode{views::to_input(E)} is expression-equivalent to: +\begin{itemize} +\item +\tcode{views::all(E)} +if \tcode{T} models \libconcept{input_range}, +does not satisfy \libconcept{common_range}, and +does not satisfy \libconcept{forward_range}. +\item +Otherwise, \tcode{to_input_view(E)}. +\end{itemize} + +\rSec3[range.to.input.view]{Class template \tcode{to_input_view}} + +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class to_input_view : public view_interface> { + V @\exposid{base_}@ = V(); // \expos + + // \ref{range.to.input.iterator}, class template \tcode{to_input_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos + + public: + to_input_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit to_input_view(V base); + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + + constexpr auto begin() requires (!@\exposconcept{simple-view}@); + constexpr auto begin() const requires @\libconcept{range}@; + + constexpr auto end() requires (!@\exposconcept{simple-view}@); + constexpr auto end() const requires @\libconcept{range}@; + + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; + }; + + template + to_input_view(R&&) -> to_input_view>; +} +\end{codeblock} + \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && - (@\libconcept{convertible_to}@, iterator_t> && - ... && @\libconcept{convertible_to}@, iterator_t>); +constexpr explicit to_input_view(V base); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes -\exposid{parent_} with \tcode{i.\exposid{parent_}} and -\exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} \begin{itemdecl} -constexpr auto operator*() const; +constexpr auto begin() requires (!@\exposconcept{simple-view}@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); -\end{codeblock} +Equivalent to: \tcode{return \exposid{iterator}(ranges::begin(\exposid{base_}));} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +constexpr auto begin() const requires @\libconcept{range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -@\exposid{next}@(); -return *this; -\end{codeblock} +Equivalent to: \tcode{return \exposid{iterator}(ranges::begin(\exposid{base_}));} \end{itemdescr} \begin{itemdecl} -constexpr void operator++(int); +constexpr auto end() requires (!@\exposconcept{simple-view}@); +constexpr auto end() const requires @\libconcept{range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{++*this}. +Equivalent to: \tcode{return ranges::end(\exposid{base_});} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{maybe-const}@>; +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; -++*this; -return tmp; -\end{codeblock} +Equivalent to: \tcode{return ranges::size(\exposid{base_});} \end{itemdescr} -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() - requires @\exposconcept{cartesian-product-is-bidirectional}@; -\end{itemdecl} +\rSec3[range.to.input.iterator]{Class template \tcode{to_input_view::\exposid{iterator}}} -\begin{itemdescr} -\pnum -\effects -Equivalent to: \begin{codeblock} -@\exposid{prev}@(); -return *this; -\end{codeblock} -\end{itemdescr} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + template + class to_input_view::@\exposid{iterator}@ { + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) - requires @\exposconcept{cartesian-product-is-bidirectional}@; -\end{itemdecl} + iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; ---*this; -return tmp; -\end{codeblock} -\end{itemdescr} + constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); // \expos -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\exposconcept{cartesian-product-is-random-access}@; -\end{itemdecl} + public: + using difference_type = range_difference_t<@\exposid{Base}@>; + using value_type = range_value_t<@\exposid{Base}@>; + using iterator_concept = input_iterator_tag; -\begin{itemdescr} -\pnum -Let \tcode{orig} be the value of \tcode{*this} before the call. + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; -Let \tcode{ret} be: -\begin{itemize} -\item -If \tcode{x > 0}, -the value of \tcode{*this} had \exposid{next} been called \tcode{x} times. -\item -Otherwise, if \tcode{x < 0}, -the value of \tcode{*this} had \exposid{prev} been called \tcode{-x} times. -\item -Otherwise, \tcode{orig}. -\end{itemize} + @\exposid{iterator}@(@\exposid{iterator}@&&) = default; + @\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default; -\pnum -\expects -\tcode{x} is in the range -$[\tcode{ranges::distance(*this, ranges::begin(*\exposid{parent_}))},$\newline -$\tcode{ranges::distance(*this, ranges::end(*\exposid{parent_}))}]$. + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; -\pnum -\effects -Sets the value of \tcode{*this} to \tcode{ret}. + constexpr iterator_t<@\exposid{Base}@> base() &&; + constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; -\pnum -\returns -\tcode{*this}. + constexpr decltype(auto) operator*() const { return *@\exposid{current_}@; } -\pnum -\complexity -Constant. -\end{itemdescr} + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\exposconcept{cartesian-product-is-random-access}@; -\end{itemdecl} + friend constexpr bool operator==(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y); -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -*this += -x; -return *this; + friend constexpr difference_type operator-(const sentinel_t<@\exposid{Base}@>& y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + + friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); + + friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) + requires @\libconcept{indirectly_swappable}@>; + }; +} \end{codeblock} -\end{itemdescr} \begin{itemdecl} -constexpr reference operator[](difference_type n) const - requires @\exposconcept{cartesian-product-is-random-access}@; +constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *((*this) + n);} +Initializes \exposid{current_} with \tcode{std::move(current)}. \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>>; +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +constexpr iterator_t<@\exposid{Base}@> base() &&; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{true} if \tcode{std::get<$i$>(x.\exposid{current_}) == ranges::end(std::get<$i$>(x.\exposid{parent_}->\exposid{bases_}))} -is \tcode{true} -for any integer $0 \le i \le \tcode{sizeof...(Vs)}$; -otherwise, \tcode{false}. -\end{itemdescr} - -\begin{itemdecl} -friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};} +\tcode{std::move(\exposid{current_)}}. \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) - requires @\exposconcept{cartesian-product-is-random-access}@; +constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return \exposid{iterator}(x) += y;} +\returns +\exposid{current_}. \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) - requires @\exposconcept{cartesian-product-is-random-access}@; +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return y + x;} +Equivalent to: +\begin{codeblock} +++@\exposid{current_}@; +return *this; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& x, difference_type y) - requires @\exposconcept{cartesian-product-is-random-access}@; +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{iterator}(x) -= y;} +Equivalent to: \tcode{++*this;} \end{itemdescr} \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{cartesian-is-sized-sentinel}@; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{distance-from}(y.\exposid{current_});} +\returns +\tcode{x.\exposid{current_} == y}. \end{itemdescr} \begin{itemdecl} -friend constexpr difference_type operator-(const @\exposid{iterator}@& i, default_sentinel_t) - requires @\exposconcept{cartesian-is-sized-sentinel}@; +friend constexpr difference_type operator-(const sentinel_t<@\exposid{Base}@>& y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum -Let \exposid{end-tuple} be an object of a type -that is a specialization of \tcode{tuple}, such that: -\begin{itemize} -\item -\tcode{std::get<0>(\exposid{end-tuple})} has the same value as -\tcode{ranges::end(std::get<0>(i.\exposid{parent_}->\exposid{ba\-ses_}))}; -\item -\tcode{std::get<$N$>(\exposid{end-tuple})} has the same value as -\tcode{ranges::begin(std::get<$N$>(i.\exposid{parent_}->\exposid{bases_}))} -for every integer $1 \le N \le \tcode{sizeof...(Vs)}$. -\end{itemize} - -\pnum -\effects -Equivalent to: \tcode{return i.\exposid{distance-from}(\exposid{end-tuple});} +\returns +\tcode{y - x.\exposid{current_}}. \end{itemdescr} \begin{itemdecl} -friend constexpr difference_type operator-(default_sentinel_t s, const @\exposid{iterator}@& i) - requires @\exposconcept{cartesian-is-sized-sentinel}@; +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return -(i - s);} +\returns +\tcode{x.\exposid{current_} - y}. \end{itemdescr} \begin{itemdecl} -friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); +friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{tuple-transform}(ranges::iter_move, i.\exposid{current_});} - -\pnum -\remarks -The exception specification is equivalent to -the logical \logop{and} of the following expressions: -\begin{itemize} -\item -\tcode{noexcept(ranges::iter_move(std::get<$N$>(i.\exposid{current_})))} -for every integer\newline $0 \le N \le \tcode{sizeof...(Vs)}$, -\item -\tcode{is_nothrow_move_constructible_v>>}\newline -for every type \tcode{T} in \tcode{First, Vs...}. -\end{itemize} +Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} \end{itemdescr} \begin{itemdecl} -friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) - requires (@\libconcept{indirectly_swappable}@>> && ... && - @\libconcept{indirectly_swappable}@>>); +friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_)}@)) + requires @\libconcept{indirectly_swappable}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -For every integer $0 \le i \le \tcode{sizeof...(Vs)}$, performs: -\begin{codeblock} -ranges::iter_swap(std::get<@$i$@>(l.@\exposid{current_}@), std::get<@$i$@>(r.@\exposid{current_}@)) -\end{codeblock} - -\pnum -\remarks -The exception specification is equivalent to the logical \logop{and} of the following expressions: -\begin{itemize} -\item -\tcode{noexcept(ranges::iter_swap(std::get<$i$>(l.\exposid{current_}), std::get<$i$>(r.\exposid{current_})))} -for\newline every integer $0 \le i \le \tcode{sizeof...(Vs)}$. -\end{itemize} +Equivalent to: \tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_});} \end{itemdescr} \rSec1[coro.generator]{Range generators} @@ -15728,12 +17928,12 @@ \begin{codeblock} namespace std { // \ref{coro.generator.class}, class template \tcode{generator} - template + template class generator; namespace pmr { - template - using generator = std::generator>; + template + using generator = std::generator>; } } \end{codeblock} @@ -15742,11 +17942,11 @@ \begin{codeblock} namespace std { - template - class @\libglobal{generator}@ : public ranges::view_interface> { + template + class @\libglobal{generator}@ : public ranges::view_interface> { private: - using @\exposid{value}@ = conditional_t, remove_cvref_t, V>; // \expos - using @\exposid{reference}@ = conditional_t, Ref&&, Ref>; // \expos + using @\exposid{value}@ = conditional_t, remove_cvref_t, Val>; // \expos + using @\exposid{reference}@ = conditional_t, Ref&&, Ref>; // \expos // \ref{coro.generator.iterator}, class \tcode{generator::\exposid{iterator}} class @\exposidnc{iterator}@; // \expos @@ -15828,7 +18028,7 @@ Initializes \exposid{coroutine_} with \tcode{exchange(other.\exposid{coroutine_}, \{\})} and \exposid{active_} with -\tcode{exchange(\brk{}other.active_, nullptr)}. +\tcode{exchange(\brk{}other.\exposid{active_}, nullptr)}. \pnum \begin{note} @@ -15932,8 +18132,8 @@ \begin{codeblock} namespace std { - template - class generator::promise_type { + template + class generator::promise_type { public: generator get_return_object() noexcept; @@ -15949,6 +18149,9 @@ template requires @\libconcept{same_as}@::yielded, yielded> auto yield_value(ranges::elements_of&&, Unused> g) noexcept; + template + requires @\libconcept{same_as}@::yielded, yielded> + auto yield_value(ranges::elements_of&, Unused> g) noexcept; template requires @\libconcept{convertible_to}@, yielded> @@ -15963,13 +18166,11 @@ requires @\libconcept{same_as}@ || @\libconcept{default_initializable}@; template - requires @\libconcept{same_as}@ || @\libconcept{convertible_to}@ - void* operator new(size_t size, allocator_arg_t, const Alloc& alloc, const Args&...); + void* operator new(size_t size, allocator_arg_t, const Alloc& alloc, const Args&...); template - requires @\libconcept{same_as}@ || @\libconcept{convertible_to}@ - void* operator new(size_t size, const This&, allocator_arg_t, const Alloc& alloc, - const Args&...); + void* operator new(size_t size, const This&, allocator_arg_t, const Alloc& alloc, + const Args&...); void operator delete(void* pointer, size_t size) noexcept; @@ -16076,6 +18277,9 @@ template requires @\libconcept{same_as}@::yielded, yielded> auto yield_value(ranges::elements_of&&, Unused> g) noexcept; +template + requires @\libconcept{same_as}@::yielded, yielded> + auto yield_value(ranges::elements_of&, Unused> g) noexcept; \end{itemdecl} \begin{itemdescr} @@ -16108,7 +18312,7 @@ \pnum \remarks -A \grammarterm{yield-expression} that calls this function +A \grammarterm{yield-expression} that calls one of these functions has type \tcode{void}\iref{expr.yield}. \end{itemdescr} @@ -16125,7 +18329,7 @@ Equivalent to: \begin{codeblock} auto nested = [](allocator_arg_t, Alloc, ranges::iterator_t i, ranges::sentinel_t s) - -> generator, Alloc> { + -> generator { for (; i != s; ++i) { co_yield static_cast(*i); } @@ -16168,11 +18372,9 @@ requires @\libconcept{same_as}@ || @\libconcept{default_initializable}@; template - requires @\libconcept{same_as}@ || @\libconcept{convertible_to}@ void* operator new(size_t size, allocator_arg_t, const Alloc& alloc, const Args&...); template - requires @\libconcept{same_as}@ || @\libconcept{convertible_to}@ void* operator new(size_t size, const This&, allocator_arg_t, const Alloc& alloc, const Args&...); \end{itemdecl} @@ -16195,6 +18397,9 @@ \pnum \mandates \tcode{allocator_traits::pointer} is a pointer type. +For the overloads with a template parameter \tcode{Alloc}, +\tcode{\libconcept{same_as} || \libconcept{convertible_to}} +is modeled. \pnum \effects @@ -16235,8 +18440,8 @@ \begin{codeblock} namespace std { - template - class generator::@\exposid{iterator}@ { + template + class generator::@\exposid{iterator}@ { public: using value_type = @\exposid{value}@; using difference_type = ptrdiff_t; diff --git a/source/regex.tex b/source/regex.tex deleted file mode 100644 index f8882f3d83..0000000000 --- a/source/regex.tex +++ /dev/null @@ -1,4001 +0,0 @@ -%!TEX root = std.tex -\rSec0[re]{Regular expressions library} -\indextext{regular expression|(} - -\rSec1[re.general]{General} - - -\pnum -This Clause describes components that \Cpp{} programs may use to -perform operations involving regular expression matching and -searching. - -\pnum -The following subclauses describe a basic regular expression class template and its -traits that can handle char-like\iref{strings.general} template arguments, -two specializations of this class template that handle sequences of \tcode{char} and \keyword{wchar_t}, -a class template that holds the -result of a regular expression match, a series of algorithms that allow a character -sequence to be operated upon by a regular expression, -and two iterator types for -enumerating regular expression matches, as summarized in \tref{re.summary}. - -\begin{libsumtab}{Regular expressions library summary}{re.summary} -\ref{re.req} & Requirements & \\ \rowsep -\ref{re.const} & Constants & \tcode{} \\ -\ref{re.badexp} & Exception type & \\ -\ref{re.traits} & Traits & \\ -\ref{re.regex} & Regular expression template & \\ -\ref{re.submatch} & Submatches & \\ -\ref{re.results} & Match results & \\ -\ref{re.alg} & Algorithms & \\ -\ref{re.iter} & Iterators & \\ \rowsep -\ref{re.grammar} & Grammar & \\ -\end{libsumtab} - -\pnum -The ECMAScript Language Specification described in Standard Ecma-262 -is called \defn{ECMA-262} in this Clause. - -\rSec1[re.req]{Requirements} - -\pnum -This subclause defines requirements on classes representing regular -expression traits. -\begin{note} -The class template -\tcode{regex_traits}, defined in \ref{re.traits}, -meets these requirements. -\end{note} - -\pnum -The class template \tcode{basic_regex}, defined in -\ref{re.regex}, needs a set of related types and -functions to complete the definition of its semantics. These types -and functions are provided as a set of member \grammarterm{typedef-name}{s} and functions -in the template parameter \tcode{traits} used by the \tcode{basic_regex} class -template. This subclause defines the semantics of these -members. - -\pnum -To specialize class template \tcode{basic_regex} for a character -container \tcode{CharT} and its related regular -expression traits class \tcode{Traits}, use \tcode{basic_regex}. - -\pnum -\indextext{regular expression traits!requirements}% -\indextext{requirements!regular expression traits}% -\indextext{regular expression!requirements}% -\indextext{locale}% -In the following requirements, -\begin{itemize} -\item -\tcode{X} denotes a traits class defining types and functions -for the character container type \tcode{charT}; -\item -\tcode{u} is an object of type \tcode{X}; -\item -\tcode{v} is an object of type \tcode{const X}; -\item -\tcode{p} is a value of type \tcode{const charT*}; -\item -\tcode{I1} and \tcode{I2} are input iterators\iref{input.iterators}; -\item -\tcode{F1} and \tcode{F2} are forward iterators\iref{forward.iterators}; -\item -\tcode{c} is a value of type \tcode{const charT}; -\item -\tcode{s} is an object of type \tcode{X::string_type}; -\item -\tcode{cs} is an object of type \tcode{const X::string_type}; -\item -\tcode{b} is a value of type \tcode{bool}; -\item -\tcode{I} is a value of type \tcode{int}; -\item -\tcode{cl} is an object of type \tcode{X::char_class_type}; and -\item -\tcode{loc} is an object of type \tcode{X::locale_type}. -\end{itemize} - -\pnum -A traits class \tcode{X} meets the regular expression traits requirements -if the following types and expressions are well-formed and have the specified -semantics. - -\begin{itemdecl} -typename X::char_type -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{charT}, -the character container type used in the implementation of class -template \tcode{basic_regex}. -\end{itemdescr} - -\begin{itemdecl} -typename X::string_type -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{basic_string} -\end{itemdescr} - -\begin{itemdecl} -typename X::locale_type -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -A copy constructible type -that represents the locale used by the traits class. -\end{itemdescr} - -\begin{itemdecl} -typename X::char_class_type -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -A bitmask type\iref{bitmask.types} -representing a particular character classification. -\end{itemdescr} - -\begin{itemdecl} -X::length(p) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{size_t} - -\pnum -\returns -The smallest \tcode{i} such that \tcode{p[i] == 0}. - -\pnum -\complexity -Linear in \tcode{i}. -\end{itemdescr} - -\begin{itemdecl} -v.translate(c) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{X::char_type} - -\pnum -\returns -A character such that for any character \tcode{d} -that is to be considered equivalent to \tcode{c} -then \tcode{v.translate(c) == v.translate(d)}. -\end{itemdescr} - -\begin{itemdecl} -v.translate_nocase(c) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{X::char_type} - -\pnum -\returns -For all characters \tcode{C} that are to be considered equivalent to \tcode{c} -when comparisons are to be performed without regard to case, -then \tcode{v.translate_nocase(c) == v.translate_nocase(C)}. -\end{itemdescr} - -\begin{itemdecl} -v.transform(F1, F2) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{X::string_type} - -\pnum -\returns -A sort key for the character sequence designated by -the iterator range \range{F1}{F2} such that -if the character sequence \range{G1}{G2} sorts before -the character sequence \range{H1}{H2} -then \tcode{v.transform(G1, G2) < v.transform(H1, H2)}. -\end{itemdescr} - -\begin{itemdecl} -v.transform_primary(F1, F2) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\indextext{regular expression traits!\idxcode{transform_primary}}% -\indextext{transform_primary@\tcode{transform_primary}!regular expression traits}% -\result -\tcode{X::string_type} - -\pnum -\returns -A sort key for the character sequence designated by -the iterator range \range{F1}{F2} such that -if the character sequence \range{G1}{G2} sorts before -the character sequence \range{H1}{H2} -when character case is not considered -then \tcode{v.transform_primary(G1, G2) < v.transform_primary(H1, H2)}. -\end{itemdescr} - -\begin{itemdecl} -v.lookup_collatename(F1, F2) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{X::string_type} - -\pnum -\returns -A sequence of characters that represents the collating element -consisting of the character sequence designated by -the iterator range \range{F1}{F2}. -Returns an empty string -if the character sequence is not a valid collating element. -\end{itemdescr} - -\begin{itemdecl} -v.lookup_classname(F1, F2, b) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{X::char_class_type} - -\pnum -\returns -Converts the character sequence designated by the iterator range -\range{F1}{F2} into a value of a bitmask type that can -subsequently be passed to \tcode{isctype}. -Values returned from \tcode{lookup_classname} can be bitwise \logop{or}'ed together; -the resulting value represents membership -in either of the corresponding character classes. -If \tcode{b} is \tcode{true}, the returned bitmask is suitable for -matching characters without regard to their case. -Returns \tcode{0} -if the character sequence is not the name of -a character class recognized by \tcode{X}. -The value returned shall be independent of -the case of the characters in the sequence. -\end{itemdescr} - -\begin{itemdecl} -v.isctype(c, cl) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{bool} - -\pnum -\returns -Returns \tcode{true} if character \tcode{c} is a member of -one of the character classes designated by \tcode{cl}, -\tcode{false} otherwise. -\end{itemdescr} - -\begin{itemdecl} -v.value(c, I) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{int} - -\pnum -\returns -Returns the value represented by the digit \textit{c} in base -\textit{I} if the character \textit{c} is a valid digit in base \textit{I}; -otherwise returns \tcode{-1}. -\begin{note} -The value of \textit{I} will only be 8, 10, or 16. -\end{note} -\end{itemdescr} - -\begin{itemdecl} -u.imbue(loc) -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{X::locale_type} - -\indextext{locale}% -\pnum -\effects -Imbues \tcode{u} with the locale \tcode{loc} and -returns the previous locale used by \tcode{u} if any. -\end{itemdescr} - -\begin{itemdecl} -v.getloc() -\end{itemdecl} - -\begin{itemdescr} -\pnum -\result -\tcode{X::locale_type} - -\pnum -\returns -Returns the current locale used by \tcode{v}, if any. \indextext{locale}% -\end{itemdescr} - -\pnum -\begin{note} -Class template \tcode{regex_traits} meets the requirements for a -regular expression traits class when it is specialized for -\tcode{char} or \keyword{wchar_t}. This class template is described in -the header \libheader{regex}, and is described in \ref{re.traits}. -\end{note} - -\rSec1[re.syn]{Header \tcode{} synopsis} - -\indexheader{regex}% -\indexlibraryglobal{basic_regex}% -\indexlibraryglobal{regex}% -\indexlibraryglobal{wregex}% -\begin{codeblock} -#include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} - -namespace std { - // \ref{re.const}, regex constants - namespace regex_constants { - using syntax_option_type = @\placeholder{T1}@; - using match_flag_type = @\placeholder{T2}@; - using error_type = @\placeholder{T3}@; - } - - // \ref{re.badexp}, class \tcode{regex_error} - class regex_error; - - // \ref{re.traits}, class template \tcode{regex_traits} - template struct regex_traits; - - // \ref{re.regex}, class template \tcode{basic_regex} - template> class basic_regex; - - using regex = basic_regex; - using wregex = basic_regex; - - // \ref{re.regex.swap}, \tcode{basic_regex} swap - template - void swap(basic_regex& e1, basic_regex& e2); - - // \ref{re.submatch}, class template \tcode{sub_match} - template - class sub_match; - - using csub_match = sub_match; - using wcsub_match = sub_match; - using ssub_match = sub_match; - using wssub_match = sub_match; - - // \ref{re.submatch.op}, \tcode{sub_match} non-member operators - template - bool operator==(const sub_match& lhs, const sub_match& rhs); - template - 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 - auto operator<=>( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); - - template - bool operator==(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); - template - 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 - auto operator<=>(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); - - template - basic_ostream& - operator<<(basic_ostream& os, const sub_match& m); - - // \ref{re.results}, class template \tcode{match_results} - template>> - class match_results; - - using cmatch = match_results; - using wcmatch = match_results; - using smatch = match_results; - using wsmatch = match_results; - - // \tcode{match_results} comparisons - template - bool operator==(const match_results& m1, - const match_results& m2); - - // \ref{re.results.swap}, \tcode{match_results} swap - template - void swap(match_results& m1, - match_results& m2); - - // \ref{re.alg.match}, function template \tcode{regex_match} - template - bool regex_match(BidirectionalIterator first, BidirectionalIterator last, - match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_match(BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_match(const charT* str, match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_match(const basic_string& s, - match_results::const_iterator, - Allocator>& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_match(const basic_string&&, - match_results::const_iterator, - Allocator>&, - const basic_regex&, - regex_constants::match_flag_type = regex_constants::match_default) = delete; - template - bool regex_match(const charT* str, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_match(const basic_string& s, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - - // \ref{re.alg.search}, function template \tcode{regex_search} - template - bool regex_search(BidirectionalIterator first, BidirectionalIterator last, - match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_search(BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_search(const charT* str, - match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_search(const charT* str, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_search(const basic_string& s, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_search(const basic_string& s, - match_results::const_iterator, - Allocator>& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - bool regex_search(const basic_string&&, - match_results::const_iterator, - Allocator>&, - const basic_regex&, - regex_constants::match_flag_type - = regex_constants::match_default) = delete; - - // \ref{re.alg.replace}, function template \tcode{regex_replace} - template - OutputIterator - regex_replace(OutputIterator out, - BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - OutputIterator - regex_replace(OutputIterator out, - BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - const charT* fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - basic_string - regex_replace(const basic_string& s, - const basic_regex& e, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - basic_string - regex_replace(const basic_string& s, - const basic_regex& e, - const charT* fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - basic_string - regex_replace(const charT* s, - const basic_regex& e, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); - template - basic_string - regex_replace(const charT* s, - const basic_regex& e, - const charT* fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); - - // \ref{re.regiter}, class template \tcode{regex_iterator} - template::value_type, - class traits = regex_traits> - class regex_iterator; - - using cregex_iterator = regex_iterator; - using wcregex_iterator = regex_iterator; - using sregex_iterator = regex_iterator; - using wsregex_iterator = regex_iterator; - - // \ref{re.tokiter}, class template \tcode{regex_token_iterator} - template::value_type, - class traits = regex_traits> - class regex_token_iterator; - - using cregex_token_iterator = regex_token_iterator; - using wcregex_token_iterator = regex_token_iterator; - using sregex_token_iterator = regex_token_iterator; - using wsregex_token_iterator = regex_token_iterator; - - namespace pmr { - template - using match_results = - std::match_results>>; - - using cmatch = match_results; - using wcmatch = match_results; - using smatch = match_results; - using wsmatch = match_results; - } -} -\end{codeblock} - -\rSec1[re.const]{Namespace \tcode{std::regex_constants}} - -\rSec2[re.const.general]{General} - -\pnum -\indexlibraryglobal{regex_constants}% -The namespace \tcode{std::regex_constants} holds -symbolic constants used by the regular expression library. This -namespace provides three types, \tcode{syntax_option_type}, -\tcode{match_flag_type}, and \tcode{error_type}, along with several -constants of these types. - -\rSec2[re.synopt]{Bitmask type \tcode{syntax_option_type}} -\indexlibraryglobal{syntax_option_type}% -\indexlibrarymember{regex_constants}{syntax_option_type}% -\begin{codeblock} -namespace std::regex_constants { - using syntax_option_type = @\textit{T1}@; - inline constexpr syntax_option_type icase = @\unspec@; - inline constexpr syntax_option_type nosubs = @\unspec@; - inline constexpr syntax_option_type optimize = @\unspec@; - inline constexpr syntax_option_type collate = @\unspec@; - inline constexpr syntax_option_type ECMAScript = @\unspec@; - inline constexpr syntax_option_type basic = @\unspec@; - inline constexpr syntax_option_type extended = @\unspec@; - inline constexpr syntax_option_type awk = @\unspec@; - inline constexpr syntax_option_type grep = @\unspec@; - inline constexpr syntax_option_type egrep = @\unspec@; - inline constexpr syntax_option_type multiline = @\unspec@; -} -\end{codeblock} - -\pnum -\indexlibraryglobal{syntax_option_type}% -\indexlibrarymember{syntax_option_type}{icase}% -\indexlibrarymember{syntax_option_type}{nosubs}% -\indexlibrarymember{syntax_option_type}{optimize}% -\indexlibrarymember{syntax_option_type}{collate}% -\indexlibrarymember{syntax_option_type}{ECMAScript}% -\indexlibrarymember{syntax_option_type}{basic}% -\indexlibrarymember{syntax_option_type}{extended}% -\indexlibrarymember{syntax_option_type}{awk}% -\indexlibrarymember{syntax_option_type}{grep}% -\indexlibrarymember{syntax_option_type}{egrep}% -The type \tcode{syntax_option_type} is an \impldef{type of \tcode{syntax_option_type}} bitmask -type\iref{bitmask.types}. Setting its elements has the effects listed in -\tref{re.synopt}. A valid value of type -\tcode{syntax_option_type} shall have at most one of the grammar elements -\tcode{ECMAScript}, \tcode{basic}, \tcode{extended}, \tcode{awk}, \tcode{grep}, \tcode{egrep}, set. -If no grammar element is set, the default grammar is \tcode{ECMAScript}. - -\begin{libefftab} - {\tcode{syntax_option_type} effects} - {re.synopt} -% -\tcode{icase} & -Specifies that matching of regular expressions against a character -container sequence shall be performed without regard to case. -\indexlibrarymember{syntax_option_type}{icase}% -\\ \rowsep -% -\tcode{nosubs} & -Specifies that no sub-expressions shall be considered to be marked, so that -when a regular expression is matched against a -character container sequence, no sub-expression matches shall be -stored in the supplied \tcode{match_results} object. -\indexlibrarymember{syntax_option_type}{nosubs}% -\\ \rowsep -% -\tcode{optimize} & -Specifies that the regular expression engine should pay more attention -to the speed with which regular expressions are matched, and less to -the speed with which regular expression objects are -constructed. Otherwise it has no detectable effect on the program -output. -\indexlibrarymember{syntax_option_type}{optimize}% -\\ \rowsep -% -\tcode{collate} & -Specifies that character ranges of the form \tcode{"[a-b]"} shall be locale -sensitive.% -\indexlibrarymember{syntax_option_type}{collate}% -\indextext{locale}% -\\ \rowsep -% -\tcode{ECMAScript} & -Specifies that the grammar recognized by the regular expression engine -shall be that used by ECMAScript in ECMA-262, as modified in~\ref{re.grammar}. -\newline \xref ECMA-262 15.10 -\indextext{ECMAScript}% -\indexlibrarymember{syntax_option_type}{ECMAScript}% -\\ \rowsep -% -\tcode{basic} & -Specifies that the grammar recognized by the regular expression engine -shall be that used by basic regular expressions in POSIX. -\newline \xref POSIX, Base Definitions and Headers, Section 9.3 -\indextext{POSIX!regular expressions}% -\indexlibrarymember{syntax_option_type}{basic}% -\\ \rowsep -% -\tcode{extended} & -Specifies that the grammar recognized by the regular expression engine -shall be that used by extended regular expressions in POSIX. -\newline \xref POSIX, Base Definitions and Headers, Section 9.4 -\indextext{POSIX!extended regular expressions}% -\indexlibrarymember{syntax_option_type}{extended}% -\\ \rowsep -% -\tcode{awk} & -Specifies that the grammar recognized by the regular expression engine -shall be that used by the utility awk in POSIX. -\indexlibrarymember{syntax_option_type}{awk}% -\\ \rowsep -% -\tcode{grep} & -Specifies that the grammar recognized by the regular expression engine -shall be that used by the utility grep in POSIX. -\indexlibrarymember{syntax_option_type}{grep}% -\\ \rowsep -% -\tcode{egrep} & -Specifies that the grammar recognized by the regular expression engine -shall be that used by the utility grep when given the -E -option in POSIX. -\indexlibrarymember{syntax_option_type}{egrep}% -\\ \rowsep -% -\tcode{multiline} & -Specifies that \tcode{\caret} shall match the beginning of a line and -\tcode{\$} shall match the end of a line, -if the \tcode{ECMAScript} engine is selected. -\indexlibrarymember{syntax_option_type}{multiline}% -\\ -% -\end{libefftab} - -\rSec2[re.matchflag]{Bitmask type \tcode{match_flag_type}} - -\indexlibraryglobal{match_flag_type}% -\indexlibrarymember{regex_constants}{match_flag_type}% -\indexlibraryglobal{match_default}% -\indexlibraryglobal{match_not_bol}% -\indexlibraryglobal{match_not_eol}% -\indexlibraryglobal{match_not_bow}% -\indexlibraryglobal{match_not_eow}% -\indexlibraryglobal{match_any}% -\indexlibraryglobal{match_not_null}% -\indexlibraryglobal{match_continuous}% -\indexlibraryglobal{match_prev_avail}% -\indexlibraryglobal{format_default}% -\indexlibraryglobal{format_sed}% -\indexlibraryglobal{format_no_copy}% -\indexlibraryglobal{format_first_only}% -\begin{codeblock} -namespace std::regex_constants { - using match_flag_type = @\textit{T2}@; - inline constexpr match_flag_type match_default = {}; - inline constexpr match_flag_type match_not_bol = @\unspec@; - inline constexpr match_flag_type match_not_eol = @\unspec@; - inline constexpr match_flag_type match_not_bow = @\unspec@; - inline constexpr match_flag_type match_not_eow = @\unspec@; - inline constexpr match_flag_type match_any = @\unspec@; - inline constexpr match_flag_type match_not_null = @\unspec@; - inline constexpr match_flag_type match_continuous = @\unspec@; - inline constexpr match_flag_type match_prev_avail = @\unspec@; - inline constexpr match_flag_type format_default = {}; - inline constexpr match_flag_type format_sed = @\unspec@; - inline constexpr match_flag_type format_no_copy = @\unspec@; - inline constexpr match_flag_type format_first_only = @\unspec@; -} -\end{codeblock} - -\pnum -\indexlibraryglobal{match_flag_type}% -The type \tcode{match_flag_type} is an -\impldef{type of \tcode{regex_constants::match_flag_type}} bitmask type\iref{bitmask.types}. -The constants of that type, except for \tcode{match_default} and -\tcode{format_default}, are bitmask elements. The \tcode{match_default} and -\tcode{format_default} constants are empty bitmasks. -Matching a regular expression against a sequence of characters -\range{first}{last} proceeds according to the rules of the grammar specified for the regular -expression object, modified according to the effects listed in \tref{re.matchflag} for -any bitmask elements set. - -\begin{longlibefftab} - {\tcode{regex_constants::match_flag_type} effects when obtaining a match against a - character container sequence \range{first}{last}.} - {re.matchflag} -% -\indexlibraryglobal{match_not_bol}% -\tcode{match_not_bol} & -The first character in the sequence \range{first}{last} shall be treated -as though it is not at the beginning of a line, so the character -\verb|^| in the regular expression shall not match \range{first}{first}. -\\ \rowsep -% -\indexlibraryglobal{match_not_eol}% -\tcode{match_not_eol} & -The last character in the sequence \range{first}{last} shall be treated -as though it is not at the end of a line, so the character -\verb|"$"| in the regular expression shall not match \range{last}{last}. -\\ \rowsep -% -\indexlibraryglobal{match_not_bow}% -\tcode{match_not_bow} & -The expression \verb|"\\b"| shall not match the -sub-sequence \range{first}{first}. -\\ \rowsep -% -\indexlibraryglobal{match_not_eow}% -\tcode{match_not_eow} & -The expression \verb|"\\b"| shall not match the -sub-sequence \range{last}{last}. -\\ \rowsep -% -\indexlibraryglobal{match_any}% -\tcode{match_any} & -If more than one match is possible then any match is an -acceptable result. -\\ \rowsep -% -\indexlibraryglobal{match_not_null}% -\tcode{match_not_null} & -The expression shall not match an empty -sequence. -\\ \rowsep -% -\indexlibraryglobal{match_continuous}% -\tcode{match_continuous} & -The expression shall only match a sub-sequence that begins at -\tcode{first}. -\\ \rowsep -% -\indexlibraryglobal{match_prev_avail}% -\tcode{match_prev_avail} & -\verb!--first! is a valid iterator position. When this flag is -set the flags \tcode{match_not_bol} and \tcode{match_not_bow} shall be ignored by the -regular expression algorithms\iref{re.alg} and iterators\iref{re.iter}. -\\ \rowsep -% -\indexlibraryglobal{format_default}% -\tcode{format_default} & -When a regular expression match is to be replaced by a -new string, the new string shall be constructed using the rules used by -the ECMAScript replace function in ECMA-262, -part 15.5.4.11 String.prototype.replace. In -addition, during search and replace operations all non-overlapping -occurrences of the regular expression shall be located and replaced, and -sections of the input that did not match the expression shall be copied -unchanged to the output string. -\\ \rowsep -% -\indexlibraryglobal{format_sed}% -\tcode{format_sed} & -When a regular expression match is to be replaced by a -new string, the new string shall be constructed using the rules used by -the sed utility in POSIX. -\\ \rowsep -% -\indexlibraryglobal{format_no_copy}% -\tcode{format_no_copy} & -During a search and replace operation, sections of -the character container sequence being searched that do not match the -regular expression shall not be copied to the output string. \\ \rowsep -% -\indexlibraryglobal{format_first_only}% -\tcode{format_first_only} & -When specified during a search and replace operation, only the -first occurrence of the regular expression shall be replaced. -\\ -\end{longlibefftab} - -\rSec2[re.err]{Implementation-defined \tcode{error_type}} -\indexlibraryglobal{error_type}% -\indexlibrarymember{regex_constants}{error_type}% -\begin{codeblock} -namespace std::regex_constants { - using error_type = @\textit{T3}@; - inline constexpr error_type error_collate = @\unspec@; - inline constexpr error_type error_ctype = @\unspec@; - inline constexpr error_type error_escape = @\unspec@; - inline constexpr error_type error_backref = @\unspec@; - inline constexpr error_type error_brack = @\unspec@; - inline constexpr error_type error_paren = @\unspec@; - inline constexpr error_type error_brace = @\unspec@; - inline constexpr error_type error_badbrace = @\unspec@; - inline constexpr error_type error_range = @\unspec@; - inline constexpr error_type error_space = @\unspec@; - inline constexpr error_type error_badrepeat = @\unspec@; - inline constexpr error_type error_complexity = @\unspec@; - inline constexpr error_type error_stack = @\unspec@; -} -\end{codeblock} - -\pnum -\indexlibraryglobal{error_type}% -\indexlibrarymember{regex_constants}{error_type}% -The type \tcode{error_type} is an \impldef{type of -\tcode{regex_constants::error_type}} enumerated type\iref{enumerated.types}. -Values of type \tcode{error_type} represent the error -conditions described in \tref{re.err}: - -\begin{longliberrtab} - {\tcode{error_type} values in the C locale} - {re.err} -\tcode{error_collate} -& -The expression contains an invalid collating element name. \\ \rowsep -% -\tcode{error_ctype} -& -The expression contains an invalid character class name. \\ \rowsep -% -\tcode{error_escape} -& -The expression contains an invalid escaped character, or a trailing -escape. \\ \rowsep -% -\tcode{error_backref} -& -The expression contains an invalid back reference. \\ \rowsep -% -\tcode{error_brack} -& -The expression contains mismatched \verb|[| and \verb|]|. \\ \rowsep -% -\tcode{error_paren} -& -The expression contains mismatched \verb|(| and \verb|)|. \\ \rowsep -% -\tcode{error_brace} -& -The expression contains mismatched \verb|{| and \verb|}| \\ \rowsep -% -\tcode{error_badbrace} -& -The expression contains an invalid range in a \verb|{}| expression. \\ -\rowsep -% -\tcode{error_range} -& -The expression contains an invalid character range, such as -\verb|[b-a]| in most encodings. \\ \rowsep -% -\tcode{error_space} -& -There is insufficient memory to convert the expression into a finite -state machine. \\ \rowsep -% -\tcode{error_badrepeat} -& -One of \verb|*?+{| is not preceded by a valid regular expression. \\ \rowsep -% -\tcode{error_complexity} -& -The complexity of an attempted match against a regular expression -exceeds a pre-set level. \\ \rowsep -% -\tcode{error_stack} -& -There is insufficient memory to determine whether the regular -expression matches the specified character sequence. \\ -% -\end{longliberrtab} - -\rSec1[re.badexp]{Class \tcode{regex_error}} -\indexlibraryglobal{regex_error}% -\begin{codeblock} -namespace std { - class regex_error : public runtime_error { - public: - explicit regex_error(regex_constants::error_type ecode); - regex_constants::error_type code() const; - }; -} -\end{codeblock} - -\pnum -The class \tcode{regex_error} defines the type of objects thrown as -exceptions to report errors from the regular expression library. - -\indexlibraryctor{regex_error}% -\begin{itemdecl} -regex_error(regex_constants::error_type ecode); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{ecode == code()}. -\end{itemdescr} - -\indexlibraryglobal{error_type}% -\indexlibrarymember{regex_constants}{error_type}% -\begin{itemdecl} -regex_constants::error_type code() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The error code that was passed to the constructor. -\end{itemdescr} - -\rSec1[re.traits]{Class template \tcode{regex_traits}} -\indexlibraryglobal{regex_traits}% -\begin{codeblock} -namespace std { - template - struct regex_traits { - using char_type = charT; - using string_type = basic_string; - using locale_type = locale; - using char_class_type = @\placeholdernc{bitmask_type}@; - - regex_traits(); - static size_t length(const char_type* p); - charT translate(charT c) const; - charT translate_nocase(charT c) const; - template - string_type transform(ForwardIterator first, ForwardIterator last) const; - template - string_type transform_primary( - ForwardIterator first, ForwardIterator last) const; - template - string_type lookup_collatename( - ForwardIterator first, ForwardIterator last) const; - template - char_class_type lookup_classname( - ForwardIterator first, ForwardIterator last, bool icase = false) const; - bool isctype(charT c, char_class_type f) const; - int value(charT ch, int radix) const; - locale_type imbue(locale_type l); - locale_type getloc() const; - }; -} -\end{codeblock} - -\pnum -\indextext{regular expression traits!requirements}% -\indextext{requirements!regular expression traits}% -The specializations \tcode{regex_traits} and -\tcode{regex_traits} meet the -requirements for a regular expression traits class\iref{re.req}. - -\indexlibrarymember{regex_traits}{char_class_type}% -\begin{itemdecl} -using char_class_type = @\textit{bitmask_type}@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The type \tcode{char_class_type} is used to represent a character -classification and is capable of holding an implementation specific -set returned by \tcode{lookup_classname}. -\end{itemdescr} - -\indexlibrarymember{length}{regex_traits}% -\begin{itemdecl} -static size_t length(const char_type* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{char_traits::length(p)}. -\end{itemdescr} - -\indexlibrarymember{regex_traits}{translate}% -\begin{itemdecl} -charT translate(charT c) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{c}. -\end{itemdescr} - -\indexlibrarymember{regex_traits}{translate_nocase}% -\begin{itemdecl} -charT translate_nocase(charT c) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{use_facet>(getloc()).tolower(c)}. -\end{itemdescr} - -\indexlibrarymember{regex_traits}{transform}% -\begin{itemdecl} -template - string_type transform(ForwardIterator first, ForwardIterator last) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -As if by: -\begin{codeblock} -string_type str(first, last); -return use_facet>( - getloc()).transform(str.data(), str.data() + str.length()); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{regex_traits}{transform_primary}% -\begin{itemdecl} -template - string_type transform_primary(ForwardIterator first, ForwardIterator last) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If -\begin{codeblock} -typeid(use_facet>) == typeid(collate_byname) -\end{codeblock} -and the form of the sort key returned -by \tcode{collate_byname::transform(first, last)} is known and -can be converted into a primary sort key then returns that key, -otherwise returns an empty string. -\end{itemdescr} - -\indexlibrarymember{regex_traits}{lookup_collatename}% -\begin{itemdecl} -template - string_type lookup_collatename(ForwardIterator first, ForwardIterator last) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A sequence of one or more characters that -represents the collating element consisting of the character -sequence designated by the iterator range \range{first}{last}. -Returns an empty string if the character sequence is not a -valid collating element. -\end{itemdescr} - -\indexlibrarymember{regex_traits}{lookup_classname}% -\begin{itemdecl} -template - char_class_type lookup_classname( - ForwardIterator first, ForwardIterator last, bool icase = false) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -An unspecified value that represents -the character classification named by the character sequence -designated by the iterator range \range{first}{last}. -If the parameter \tcode{icase} is \tcode{true} then the returned mask identifies the -character classification without regard to the case of the characters being -matched, otherwise it does honor the case of the characters being -matched. -\begin{footnote} -For example, if the parameter \tcode{icase} is \tcode{true} then -\tcode{[[:lower:]]} is the same as \tcode{[[:alpha:]]}. -\end{footnote} -The value -returned shall be independent of the case of the characters in -the character sequence. If the name -is not recognized then returns \tcode{char_class_type()}. - -\pnum -\remarks -For \tcode{regex_traits}, at least the narrow character names -in \tref{re.traits.classnames} shall be recognized. -For \tcode{regex_traits}, at least the wide character names -in \tref{re.traits.classnames} shall be recognized. -\end{itemdescr} - -\indexlibrarymember{regex_traits}{isctype}% -\begin{itemdecl} -bool isctype(charT c, char_class_type f) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Determines if the character \tcode{c} is a member of the character -classification represented by \tcode{f}. - -\pnum -\returns -Given the following function declaration: -\begin{codeblock} -// for exposition only -template - ctype_base::mask convert(typename regex_traits::char_class_type f); -\end{codeblock} -that returns a value in which each \tcode{ctype_base::mask} value corresponding to -a value in \tcode{f} named in \tref{re.traits.classnames} is set, then the -result is determined as if by: -\begin{codeblock} -ctype_base::mask m = convert(f); -const ctype& ct = use_facet>(getloc()); -if (ct.is(m, c)) { - return true; -} else if (c == ct.widen('_')) { - charT w[1] = { ct.widen('w') }; - char_class_type x = lookup_classname(w, w+1); - return (f&x) == x; -} else { - return false; -} -\end{codeblock} -\begin{example} -\begin{codeblock} -regex_traits t; -string d("d"); -string u("upper"); -regex_traits::char_class_type f; -f = t.lookup_classname(d.begin(), d.end()); -f |= t.lookup_classname(u.begin(), u.end()); -ctype_base::mask m = convert(f); // \tcode{m == ctype_base::digit|ctype_base::upper} -\end{codeblock} -\end{example} -\begin{example} -\begin{codeblock} -regex_traits t; -string w("w"); -regex_traits::char_class_type f; -f = t.lookup_classname(w.begin(), w.end()); -t.isctype('A', f); // returns \tcode{true} -t.isctype('_', f); // returns \tcode{true} -t.isctype(' ', f); // returns \tcode{false} -\end{codeblock} -\end{example} -\end{itemdescr} - -\indexlibrarymember{value}{regex_traits}% -\begin{itemdecl} -int value(charT ch, int radix) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The value of \tcode{radix} is 8, 10, or 16. - -\pnum -\returns -The value represented by the digit \tcode{ch} in base -\tcode{radix} if the character \tcode{ch} is a valid digit in base -\tcode{radix}; otherwise returns \tcode{-1}. -\end{itemdescr} - -\indexlibraryglobal{locale}% -\indexlibraryglobal{imbue}% -\begin{itemdecl} -locale_type imbue(locale_type loc); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Imbues \keyword{this} with a copy of the -locale \tcode{loc}. -\begin{note} -Calling \tcode{imbue} with a -different locale than the one currently in use invalidates all cached -data held by \tcode{*this}. -\end{note} - -\pnum -\ensures -\tcode{getloc() == loc}. - -\pnum -\returns -If no locale has been previously imbued then a copy of the -global locale in effect at the time of construction of \tcode{*this}, -otherwise a copy of the last argument passed to \tcode{imbue}. -\end{itemdescr} - -\indexlibraryglobal{locale}% -\indexlibraryglobal{getloc}% -\begin{itemdecl} -locale_type getloc() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -If no locale has been imbued then a copy of the global locale -in effect at the time of construction of \tcode{*this}, otherwise a copy of -the last argument passed to \tcode{imbue}. -\end{itemdescr} - -\begin{floattable}{Character class names and corresponding \tcode{ctype} masks}{re.traits.classnames}{lll} -\topline -\lhdr{Narrow character name} & \chdr{Wide character name} & \rhdr{Corresponding \tcode{ctype_base::mask} value} \\\capsep -\tcode{"alnum"} & \tcode{L"alnum"} & \tcode{ctype_base::alnum} \\ \rowsep -\tcode{"alpha"} & \tcode{L"alpha"} & \tcode{ctype_base::alpha} \\ \rowsep -\tcode{"blank"} & \tcode{L"blank"} & \tcode{ctype_base::blank} \\ \rowsep -\tcode{"cntrl"} & \tcode{L"cntrl"} & \tcode{ctype_base::cntrl} \\ \rowsep -\tcode{"digit"} & \tcode{L"digit"} & \tcode{ctype_base::digit} \\ \rowsep -\tcode{"d"} & \tcode{L"d"} & \tcode{ctype_base::digit} \\ \rowsep -\tcode{"graph"} & \tcode{L"graph"} & \tcode{ctype_base::graph} \\ \rowsep -\tcode{"lower"} & \tcode{L"lower"} & \tcode{ctype_base::lower} \\ \rowsep -\tcode{"print"} & \tcode{L"print"} & \tcode{ctype_base::print} \\ \rowsep -\tcode{"punct"} & \tcode{L"punct"} & \tcode{ctype_base::punct} \\ \rowsep -\tcode{"space"} & \tcode{L"space"} & \tcode{ctype_base::space} \\ \rowsep -\tcode{"s"} & \tcode{L"s"} & \tcode{ctype_base::space} \\ \rowsep -\tcode{"upper"} & \tcode{L"upper"} & \tcode{ctype_base::upper} \\ \rowsep -\tcode{"w"} & \tcode{L"w"} & \tcode{ctype_base::alnum} \\ \rowsep -\tcode{"xdigit"} & \tcode{L"xdigit"} & \tcode{ctype_base::xdigit} \\ -\end{floattable} - -\rSec1[re.regex]{Class template \tcode{basic_regex}} - -\rSec2[re.regex.general]{General} -\indexlibraryglobal{basic_regex}% - -\pnum -For a char-like type \tcode{charT}, specializations of class -template \tcode{basic_regex} represent regular expressions constructed -from character sequences of \tcode{charT} characters. In the rest -of~\ref{re.regex}, \tcode{charT} denotes a given char-like -type. Storage for a regular expression is allocated and freed as -necessary by the member functions of class \tcode{basic_regex}. - -\pnum -Objects of type specialization of \tcode{basic_regex} are responsible for -converting the sequence of \tcode{charT} objects to an internal -representation. It is not specified what form this representation -takes, nor how it is accessed by algorithms that operate on regular -expressions. -\begin{note} -Implementations will typically declare -some function templates as friends of \tcode{basic_regex} to achieve -this. -\end{note} - -\pnum -\indexlibraryglobal{regex_error}% -The functions described in \ref{re.regex} report errors by throwing -exceptions of type \tcode{regex_error}. - -\indexlibraryglobal{basic_regex}% -\begin{codeblock} -namespace std { - template> - class basic_regex { - public: - // types - using value_type = charT; - using traits_type = traits; - using string_type = typename traits::string_type; - using flag_type = regex_constants::syntax_option_type; - using locale_type = typename traits::locale_type; - - // \ref{re.synopt}, constants - static constexpr flag_type icase = regex_constants::icase; - static constexpr flag_type nosubs = regex_constants::nosubs; - static constexpr flag_type optimize = regex_constants::optimize; - static constexpr flag_type collate = regex_constants::collate; - static constexpr flag_type ECMAScript = regex_constants::ECMAScript; - static constexpr flag_type basic = regex_constants::basic; - static constexpr flag_type extended = regex_constants::extended; - static constexpr flag_type awk = regex_constants::awk; - static constexpr flag_type grep = regex_constants::grep; - static constexpr flag_type egrep = regex_constants::egrep; - static constexpr flag_type multiline = regex_constants::multiline; - - // \ref{re.regex.construct}, construct/copy/destroy - basic_regex(); - explicit basic_regex(const charT* p, flag_type f = regex_constants::ECMAScript); - basic_regex(const charT* p, size_t len, flag_type f = regex_constants::ECMAScript); - basic_regex(const basic_regex&); - basic_regex(basic_regex&&) noexcept; - template - explicit basic_regex(const basic_string& s, - flag_type f = regex_constants::ECMAScript); - template - basic_regex(ForwardIterator first, ForwardIterator last, - flag_type f = regex_constants::ECMAScript); - basic_regex(initializer_list il, flag_type f = regex_constants::ECMAScript); - - ~basic_regex(); - - // \ref{re.regex.assign}, assign - basic_regex& operator=(const basic_regex& e); - basic_regex& operator=(basic_regex&& e) noexcept; - basic_regex& operator=(const charT* p); - basic_regex& operator=(initializer_list il); - template - basic_regex& operator=(const basic_string& s); - - basic_regex& assign(const basic_regex& e); - basic_regex& assign(basic_regex&& e) noexcept; - basic_regex& assign(const charT* p, flag_type f = regex_constants::ECMAScript); - basic_regex& assign(const charT* p, size_t len, flag_type f = regex_constants::ECMAScript); - template - basic_regex& assign(const basic_string& s, - flag_type f = regex_constants::ECMAScript); - template - basic_regex& assign(InputIterator first, InputIterator last, - flag_type f = regex_constants::ECMAScript); - basic_regex& assign(initializer_list, - flag_type f = regex_constants::ECMAScript); - - // \ref{re.regex.operations}, const operations - unsigned mark_count() const; - flag_type flags() const; - - // \ref{re.regex.locale}, locale - locale_type imbue(locale_type loc); - locale_type getloc() const; - - // \ref{re.regex.swap}, swap - void swap(basic_regex&); - }; - - template - basic_regex(ForwardIterator, ForwardIterator, - regex_constants::syntax_option_type = regex_constants::ECMAScript) - -> basic_regex::value_type>; -} -\end{codeblock} - -\rSec2[re.regex.construct]{Constructors} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -basic_regex(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{*this} does not match any character sequence. -\end{itemdescr} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -explicit basic_regex(const charT* p, flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\range{p}{p + char_traits::length(p)} is a valid range. - -\pnum -\effects -The object's internal finite state machine -is constructed from the regular expression contained in -the sequence of characters -\range{p}{p + char_traits::\brk{}length(p)}, and -interpreted according to the flags \tcode{f}. - -\pnum -\ensures -\tcode{flags()} returns \tcode{f}. -\tcode{mark_count()} returns the number of marked sub-expressions -within the expression. - -\pnum -\throws -\tcode{regex_error} if -\range{p}{p + char_traits::length(p)} is not a valid regular expression. -\end{itemdescr} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -basic_regex(const charT* p, size_t len, flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\range{p}{p + len} is a valid range. - -\pnum -\effects -The object's internal finite state machine -is constructed from the regular expression contained in -the sequence of characters \range{p}{p + len}, and -interpreted according the flags specified in \tcode{f}. - -\pnum -\ensures -\tcode{flags()} returns \tcode{f}. -\tcode{mark_count()} returns the number of marked sub-expressions -within the expression. - -\pnum -\throws -\tcode{regex_error} if \range{p}{p + len} is not a valid regular expression. -\end{itemdescr} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -basic_regex(const basic_regex& e); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{flags()} and \tcode{mark_count()} return -\tcode{e.flags()} and \tcode{e.mark_count()}, respectively. -\end{itemdescr} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -basic_regex(basic_regex&& e) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{flags()} and \tcode{mark_count()} return the values that -\tcode{e.flags()} and \tcode{e.mark_count()}, respectively, had before construction. -\end{itemdescr} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -template - explicit basic_regex(const basic_string& s, - flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -The object's internal finite state machine -is constructed from the regular expression contained in -the string \tcode{s}, and -interpreted according to the flags specified in \tcode{f}. - -\pnum -\ensures -\tcode{flags()} returns \tcode{f}. -\tcode{mark_count()} returns the number of marked sub-expressions -within the expression. - -\pnum -\throws -\tcode{regex_error} if \tcode{s} is not a valid regular expression. -\end{itemdescr} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -template - basic_regex(ForwardIterator first, ForwardIterator last, - flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -The object's internal finite state machine -is constructed from the regular expression contained in -the sequence of characters \range{first}{last}, and -interpreted according to the flags specified in \tcode{f}. - -\pnum -\ensures -\tcode{flags()} returns \tcode{f}. -\tcode{mark_count()} returns the number of marked sub-expressions -within the expression. - -\pnum -\throws -\tcode{regex_error} if the sequence \range{first}{last} is not a -valid regular expression. -\end{itemdescr} - -\indexlibraryctor{basic_regex}% -\begin{itemdecl} -basic_regex(initializer_list il, flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Same as \tcode{basic_regex(il.begin(), il.end(), f)}. -\end{itemdescr} - -\rSec2[re.regex.assign]{Assignment} - -\indexlibrarymember{basic_regex}{operator=}% -\begin{itemdecl} -basic_regex& operator=(const basic_regex& e); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{flags()} and \tcode{mark_count()} return -\tcode{e.flags()} and \tcode{e.mark_count()}, respectively. -\end{itemdescr} - -\indexlibrarymember{basic_regex}{operator=}% -\begin{itemdecl} -basic_regex& operator=(basic_regex&& e) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{flags()} and \tcode{mark_count()} return the values that -\tcode{e.flags()} and \tcode{e.mark_count()}, respectively, had before assignment. -\tcode{e} is in a valid state with unspecified value. -\end{itemdescr} - -\indexlibrarymember{basic_regex}{operator=}% -\begin{itemdecl} -basic_regex& operator=(const charT* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(p);} -\end{itemdescr} - -\indexlibrarymember{basic_regex}{operator=}% -\begin{itemdecl} -basic_regex& operator=(initializer_list il); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(il.begin(), il.end());} -\end{itemdescr} - -\indexlibrarymember{basic_regex}{operator=}% -\begin{itemdecl} -template - basic_regex& operator=(const basic_string& s); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(s);} -\end{itemdescr} - -\indexlibrarymember{basic_regex}{assign}% -\begin{itemdecl} -basic_regex& assign(const basic_regex& e); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return *this = e;} -\end{itemdescr} - -\indexlibrarymember{basic_regex}{assign}% -\begin{itemdecl} -basic_regex& assign(basic_regex&& e) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return *this = std::move(e);} -\end{itemdescr} - -\indexlibrarymember{basic_regex}{assign}% -\begin{itemdecl} -basic_regex& assign(const charT* p, flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(string_type(p), f);} -\end{itemdescr} - -\indexlibrarymember{basic_regex}{assign}% -\begin{itemdecl} -basic_regex& assign(const charT* p, size_t len, flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(string_type(p, len), f);} -\end{itemdescr} - -\indexlibrarymember{basic_regex}{assign}% -\begin{itemdecl} -template - basic_regex& assign(const basic_string& s, - flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Assigns the regular expression contained in the string -\tcode{s}, interpreted according the flags specified in \tcode{f}. -If an exception is thrown, \tcode{*this} is unchanged. - -\pnum -\ensures -If no exception is thrown, -\tcode{flags()} returns \tcode{f} and \tcode{mark_count()} -returns the number of marked sub-expressions within the expression. - -\pnum -\returns -\tcode{*this}. - -\pnum -\throws -\tcode{regex_error} if \tcode{s} is not a valid regular expression. -\end{itemdescr} - -\indexlibrarymember{basic_regex}{assign}% -\begin{itemdecl} -template - basic_regex& assign(InputIterator first, InputIterator last, - flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(string_type(first, last), f);} -\end{itemdescr} - -\indexlibrarymember{assign}{basic_regex}% -\begin{itemdecl} -basic_regex& assign(initializer_list il, - flag_type f = regex_constants::ECMAScript); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(il.begin(), il.end(), f);} -\end{itemdescr} - - -\rSec2[re.regex.operations]{Constant operations} - -\indexlibrarymember{mark_count}{basic_regex}% -\begin{itemdecl} -unsigned mark_count() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Returns the number of marked sub-expressions within the -regular expression. -\end{itemdescr} - -\indexlibrarymember{flag_type}{basic_regex}% -\begin{itemdecl} -flag_type flags() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Returns a copy of the regular expression syntax flags that -were passed to the object's constructor or to the last call -to \tcode{assign}. -\end{itemdescr} - -\rSec2[re.regex.locale]{Locale}% -\indexlibraryglobal{locale} - -\indexlibrarymember{imbue}{basic_regex}% -\begin{itemdecl} -locale_type imbue(locale_type loc); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Returns the result of \tcode{traits_inst.imbue(loc)} where -\tcode{traits_inst} is a (default-initialized) instance of the template -type argument \tcode{traits} stored within the object. After a call -to \tcode{imbue} the \tcode{basic_regex} object does not match any -character sequence. -\end{itemdescr} - -\indexlibrarymember{getloc}{basic_regex}% -\begin{itemdecl} -locale_type getloc() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Returns the result of \tcode{traits_inst.getloc()} where -\tcode{traits_inst} is a (default-initialized) instance of the template -parameter \tcode{traits} stored within the object. -\end{itemdescr} - -\rSec2[re.regex.swap]{Swap} -\indexlibrarymember{basic_regex}{swap}% - -\indexlibrarymember{swap}{basic_regex}% -\begin{itemdecl} -void swap(basic_regex& e); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Swaps the contents of the two regular expressions. - -\pnum -\ensures -\tcode{*this} contains the regular expression -that was in \tcode{e}, \tcode{e} contains the regular expression that -was in \tcode{*this}. - -\pnum -\complexity -Constant time. -\end{itemdescr} - -\rSec2[re.regex.nonmemb]{Non-member functions} - -\indexlibrarymember{basic_regex}{swap}% -\begin{itemdecl} -template - void swap(basic_regex& lhs, basic_regex& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{lhs.swap(rhs)}. -\end{itemdescr} - -\rSec1[re.submatch]{Class template \tcode{sub_match}} - -\rSec2[re.submatch.general]{General} -\pnum -\indexlibraryglobal{sub_match}% -Class template \tcode{sub_match} denotes the sequence of characters matched -by a particular marked sub-expression. - -\begin{codeblock} -namespace std { - template - class sub_match : public pair { - public: - using value_type = - typename iterator_traits::value_type; - using difference_type = - typename iterator_traits::difference_type; - using iterator = BidirectionalIterator; - using string_type = basic_string; - - bool matched; - - constexpr sub_match(); - - difference_type length() const; - operator string_type() const; - string_type str() const; - - int compare(const sub_match& s) const; - int compare(const string_type& s) const; - int compare(const value_type* s) const; - - void swap(sub_match& s) noexcept(@\seebelow@); - }; -} -\end{codeblock} - - -\rSec2[re.submatch.members]{Members} - -\indexlibraryctor{sub_match}% -\begin{itemdecl} -constexpr sub_match(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Value-initializes the \tcode{pair} base class subobject and the member -\tcode{matched}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{length}% -\begin{itemdecl} -difference_type length() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{matched ?\ distance(first, second) :\ 0}. -\end{itemdescr} - -\indexlibrarymember{operator basic_string}{sub_match}% -\begin{itemdecl} -operator string_type() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{matched ?\ string_type(first, second) :\ string_type()}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{str}% -\begin{itemdecl} -string_type str() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{matched ?\ string_type(first, second) :\ string_type()}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{compare}% -\begin{itemdecl} -int compare(const sub_match& s) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{str().compare(s.str())}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{compare}% -\begin{itemdecl} -int compare(const string_type& s) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{str().compare(s)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{compare}% -\begin{itemdecl} -int compare(const value_type* s) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{str().compare(s)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{swap}% -\begin{itemdecl} -void swap(sub_match& s) noexcept(@\seebelow@); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{BidirectionalIterator} meets -the \oldconcept{Swappable} requirements\iref{swappable.requirements}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -this->pair::swap(s); -std::swap(matched, s.matched); -\end{codeblock} - -\pnum -\remarks -The exception specification is equivalent to -\tcode{is_nothrow_swappable_v}. -\end{itemdescr} - -\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 - 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 - auto operator<=>(const sub_match& lhs, const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{static_cast<\placeholdernc{SM-CAT}(BiIter)>(lhs.compare(rhs) <=> 0)}. -\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 -\begin{codeblock} -lhs.compare(typename sub_match::string_type(rhs.data(), rhs.size())) == 0 -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{operator<=>}{sub_match}% -\begin{itemdecl} -template - auto operator<=>( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\begin{codeblock} -static_cast<@\placeholdernc{SM-CAT}@(BiIter)>(lhs.compare( - typename sub_match::string_type(rhs.data(), rhs.size())) - <=> 0 - ) -\end{codeblock} -\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 - auto operator<=>(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{static_cast<\placeholdernc{SM-CAT}(BiIter)>(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.compare(typename sub_match::string_type(1, rhs)) == 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<=>}% -\begin{itemdecl} -template - auto operator<=>(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\begin{codeblock} -static_cast<@\placeholdernc{SM-CAT}@(BiIter)>(lhs.compare( - typename sub_match::string_type(1, rhs)) - <=> 0 - ) -\end{codeblock} -\end{itemdescr} - -\indexlibraryglobal{basic_ostream}% -\indexlibrarymember{sub_match}{operator<<}% -\begin{itemdecl} -template - basic_ostream& - operator<<(basic_ostream& os, const sub_match& m); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{os << m.str()}. -\end{itemdescr} - -\rSec1[re.results]{Class template \tcode{match_results}} - -\rSec2[re.results.general]{General} -\pnum -\indexlibraryglobal{match_results}% -Class template \tcode{match_results} denotes a collection of character -sequences representing the result of a regular expression -match. Storage for the collection is allocated and freed as necessary -by the member functions of class template \tcode{match_results}. - -\pnum -\indextext{requirements!container}% -\indextext{requirements!sequence}% -The class template \tcode{match_results} meets the requirements of an -allocator-aware container\iref{container.alloc.reqmts} and of -a sequence container\iref{container.requirements.general,sequence.reqmts} -except that only -copy assignment, -move assignment, and -operations defined for const-qualified sequence containers -are supported and -that the semantics of the comparison operator functions are different from those -required for a container. - -\pnum -A default-constructed \tcode{match_results} object has no fully established result state. A -match result is \defn{ready} when, as a consequence of a completed regular expression match -modifying such an object, its result state becomes fully established. The effects of calling -most member functions from a \tcode{match_results} object that is not ready are undefined. - -\pnum -\indexlibrarymember{match_results}{matched}% -The \tcode{sub_match} object stored at index 0 represents sub-expression 0, -i.e., the whole match. In this case the \tcode{sub_match} member -\tcode{matched} is always \tcode{true}. The \tcode{sub_match} -object stored at index \tcode{n} denotes what matched the marked -sub-expression \tcode{n} within the matched expression. If the -sub-expression \tcode{n} participated in a regular expression -match then the \tcode{sub_match} member \tcode{matched} evaluates to \tcode{true}, and -members \tcode{first} and \tcode{second} denote the range of characters -\range{first}{second} which formed that -match. Otherwise \tcode{matched} is \tcode{false}, and members \tcode{first} -and \tcode{second} point to the end of the sequence -that was searched. -\begin{note} -The \tcode{sub_match} objects representing -different sub-expressions that did not participate in a regular expression -match need not be distinct. -\end{note} - -\begin{codeblock} -namespace std { - template>> - class match_results { - public: - using value_type = sub_match; - using const_reference = const value_type&; - using reference = value_type&; - using const_iterator = @\impdefx{type of \tcode{match_results::const_iterator}}@; - using iterator = const_iterator; - using difference_type = - typename iterator_traits::difference_type; - using size_type = typename allocator_traits::size_type; - using allocator_type = Allocator; - using char_type = - typename iterator_traits::value_type; - using string_type = basic_string; - - // \ref{re.results.const}, construct/copy/destroy - match_results() : match_results(Allocator()) {} - explicit match_results(const Allocator& a); - match_results(const match_results& m); - match_results(const match_results& m, const Allocator& a); - match_results(match_results&& m) noexcept; - match_results(match_results&& m, const Allocator& a); - match_results& operator=(const match_results& m); - match_results& operator=(match_results&& m); - ~match_results(); - - // \ref{re.results.state}, state - bool ready() const; - - // \ref{re.results.size}, size - size_type size() const; - size_type max_size() const; - [[nodiscard]] bool empty() const; - - // \ref{re.results.acc}, element access - difference_type length(size_type sub = 0) const; - difference_type position(size_type sub = 0) const; - string_type str(size_type sub = 0) const; - const_reference operator[](size_type n) const; - - const_reference prefix() const; - const_reference suffix() const; - const_iterator begin() const; - const_iterator end() const; - const_iterator cbegin() const; - const_iterator cend() const; - - // \ref{re.results.form}, format - template - OutputIter - format(OutputIter out, - const char_type* fmt_first, const char_type* fmt_last, - regex_constants::match_flag_type flags = regex_constants::format_default) const; - template - OutputIter - format(OutputIter out, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::format_default) const; - template - basic_string - format(const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::format_default) const; - string_type - format(const char_type* fmt, - regex_constants::match_flag_type flags = regex_constants::format_default) const; - - // \ref{re.results.all}, allocator - allocator_type get_allocator() const; - - // \ref{re.results.swap}, swap - void swap(match_results& that); - }; -} -\end{codeblock} - -\rSec2[re.results.const]{Constructors} - -\pnum -\tref{re.results.const} lists the postconditions of -\tcode{match_results} copy/move constructors and copy/move assignment operators. -For move operations, -the results of the expressions depending on the parameter \tcode{m} denote -the values they had before the respective function calls. - -\indexlibraryctor{match_results}% -\begin{itemdecl} -explicit match_results(const Allocator& a); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -The stored \tcode{Allocator} value is constructed from \tcode{a}. - -\pnum -\ensures -\tcode{ready()} returns \tcode{false}. -\tcode{size()} returns \tcode{0}. -\end{itemdescr} - -\indexlibraryctor{match_results}% -\begin{itemdecl} -match_results(const match_results& m); -match_results(const match_results& m, const Allocator& a); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -For the first form, -the stored \tcode{Allocator} value is obtained -as specified in \ref{container.reqmts}. -For the second form, -the stored \tcode{Allocator} value is constructed from \tcode{a}. - -\pnum -\ensures -As specified in \tref{re.results.const}. -\end{itemdescr} - -\indexlibraryctor{match_results}% -\begin{itemdecl} -match_results(match_results&& m) noexcept; -match_results(match_results&& m, const Allocator& a); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -For the first form, -the stored \tcode{Allocator} value is move constructed from \tcode{m.get_allocator()}. -For the second form, -the stored \tcode{Allocator} value is constructed from \tcode{a}. - -\pnum -\ensures -As specified in \tref{re.results.const}. - -\pnum -\throws -The second form throws nothing if -\tcode{a == m.get_allocator()} is \tcode{true}. -\end{itemdescr} - -\indexlibrarymember{match_results}{operator=}% -\begin{itemdecl} -match_results& operator=(const match_results& m); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -As specified in \tref{re.results.const}. -\end{itemdescr} - -\indexlibrarymember{match_results}{operator=}% -\begin{itemdecl} -match_results& operator=(match_results&& m); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -As specified in \tref{re.results.const}. -\end{itemdescr} - -\begin{libefftabvalue} - {\tcode{match_results} copy/move operation postconditions} - {re.results.const} -\tcode{ready()} & \tcode{m.ready()} \\ \rowsep -\tcode{size()} & \tcode{m.size()} \\ \rowsep -\tcode{str(n)} & \tcode{m.str(n)} for all non-negative integers \tcode{n < m.size()} \\ \rowsep -\tcode{prefix()} & \tcode{m.prefix()} \\ \rowsep -\tcode{suffix()} & \tcode{m.suffix()} \\ \rowsep -\tcode{(*this)[n]} & \tcode{m[n]} for all non-negative integers \tcode{n < m.size()} \\ \rowsep -\tcode{length(n)} & \tcode{m.length(n)} for all non-negative integers \tcode{n < m.size()} \\ \rowsep -\tcode{position(n)} & \tcode{m.position(n)} for all non-negative integers \tcode{n < m.size()} \\ -\end{libefftabvalue} - -\rSec2[re.results.state]{State} - -\indexlibrarymember{match_results}{ready}% -\begin{itemdecl} -bool ready() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if \tcode{*this} has a fully established result state, otherwise -\tcode{false}. -\end{itemdescr} - -\rSec2[re.results.size]{Size} - -\indexlibrarymember{match_results}{size}% -\begin{itemdecl} -size_type size() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -One plus the number of marked sub-expressions in the -regular expression that was matched if \tcode{*this} represents the -result of a successful match. Otherwise returns \tcode{0}. -\begin{note} -The state of a \tcode{match_results} object can be modified -only by passing that object to \tcode{regex_match} or \tcode{regex_search}. -Subclauses~\ref{re.alg.match} and~\ref{re.alg.search} specify the -effects of those algorithms on their \tcode{match_results} arguments. -\end{note} -\end{itemdescr} - -\indexlibrarymember{match_results}{max_size}% -\begin{itemdecl} -size_type max_size() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The maximum number of \tcode{sub_match} elements that can be -stored in \tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{match_results}{empty}% -\begin{itemdecl} -[[nodiscard]] bool empty() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{size() == 0}. -\end{itemdescr} - -\rSec2[re.results.acc]{Element access} - -\indexlibrarymember{length}{match_results}% -\begin{itemdecl} -difference_type length(size_type sub = 0) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\returns -\tcode{(*this)[sub].length()}. -\end{itemdescr} - -\indexlibrarymember{position}{match_results}% -\begin{itemdecl} -difference_type position(size_type sub = 0) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\returns -The distance from the start of the target sequence -to \tcode{(*this)[sub].first}. -\end{itemdescr} - -\indexlibrarymember{match_results}{str}% -\begin{itemdecl} -string_type str(size_type sub = 0) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\returns -\tcode{string_type((*this)[sub])}. -\end{itemdescr} - -\indexlibrarymember{match_results}{operator[]}% -\begin{itemdecl} -const_reference operator[](size_type n) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\returns -A reference to the \tcode{sub_match} object representing the -character sequence that matched marked sub-expression \tcode{n}. If \tcode{n == 0} -then returns a reference to a \tcode{sub_match} object representing the -character sequence that matched the whole regular expression. If -\tcode{n >= size()} then returns a \tcode{sub_match} object representing an -unmatched sub-expression. -\end{itemdescr} - -\indexlibrarymember{match_results}{prefix}% -\begin{itemdecl} -const_reference prefix() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\returns -A reference to the \tcode{sub_match} object representing the -character sequence from the start of the string being -matched/searched to the start of the match found. -\end{itemdescr} - -\indexlibrarymember{match_results}{suffix}% -\begin{itemdecl} -const_reference suffix() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\returns -A reference to the \tcode{sub_match} object representing the -character sequence from the end of the match found to the end of the -string being matched/searched. -\end{itemdescr} - -\indexlibrarymember{match_results}{begin}% -\begin{itemdecl} -const_iterator begin() const; -const_iterator cbegin() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A starting iterator that enumerates over all the -sub-expressions stored in \tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{match_results}{end}% -\begin{itemdecl} -const_iterator end() const; -const_iterator cend() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A terminating iterator that enumerates over all the -sub-expressions stored in \tcode{*this}. -\end{itemdescr} - -\rSec2[re.results.form]{Formatting} - -\indexlibrarymember{match_results}{format}% -\begin{itemdecl} -template - OutputIter format( - OutputIter out, - const char_type* fmt_first, const char_type* fmt_last, - regex_constants::match_flag_type flags = regex_constants::format_default) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true} and \tcode{OutputIter} meets the requirements for a -\oldconcept{OutputIterator}\iref{output.iterators}. - -\pnum -\effects -Copies the character sequence \range{fmt_first}{fmt_last} to -OutputIter \tcode{out}. Replaces each format specifier or escape -sequence in the copied range with either the character(s) it represents or -the sequence of characters within \tcode{*this} to which it refers. -The bitmasks specified in \tcode{flags} determine which format -specifiers and escape sequences are recognized. - -\pnum -\returns -\tcode{out}. -\end{itemdescr} - -\indexlibrarymember{match_results}{format}% -\begin{itemdecl} -template - OutputIter format( - OutputIter out, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::format_default) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return format(out, fmt.data(), fmt.data() + fmt.size(), flags); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{match_results}{format}% -\begin{itemdecl} -template - basic_string format( - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::format_default) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\effects -Constructs an empty string \tcode{result} of type \tcode{basic_string} and -calls: -\begin{codeblock} -format(back_inserter(result), fmt, flags); -\end{codeblock} - -\pnum -\returns -\tcode{result}. -\end{itemdescr} - -\indexlibrarymember{match_results}{format}% -\begin{itemdecl} -string_type format( - const char_type* fmt, - regex_constants::match_flag_type flags = regex_constants::format_default) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{ready() == true}. - -\pnum -\effects -Constructs an empty string \tcode{result} of type \tcode{string_type} and -calls: -\begin{codeblock} -format(back_inserter(result), fmt, fmt + char_traits::length(fmt), flags); -\end{codeblock} - -\pnum -\returns -\tcode{result}. -\end{itemdescr} - -\rSec2[re.results.all]{Allocator}% - -\indexlibrarymember{get_allocator}{match_results}% -\begin{itemdecl} -allocator_type get_allocator() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A copy of the Allocator that was passed to the object's constructor or, if that -allocator has been replaced, a copy of the most recent replacement. -\end{itemdescr} - -\rSec2[re.results.swap]{Swap} - -\indexlibrarymember{match_results}{swap}% -\begin{itemdecl} -void swap(match_results& that); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Swaps the contents of the two sequences. - -\pnum -\ensures -\tcode{*this} contains the sequence of matched -sub-expressions that were in \tcode{that}, \tcode{that} contains the -sequence of matched sub-expressions that were in \tcode{*this}. - -\pnum -\complexity -Constant time. -\end{itemdescr} - -\indexlibrarymember{match_results}{swap}% -\begin{itemdecl} -template - void swap(match_results& m1, - match_results& m2); -\end{itemdecl} - -\pnum -\effects -As if by \tcode{m1.swap(m2)}. - -\rSec2[re.results.nonmember]{Non-member functions} - -\indexlibrarymember{operator==}{match_results}% -\begin{itemdecl} -template -bool operator==(const match_results& m1, - const match_results& m2); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if neither match result is ready, \tcode{false} if one match result is ready and the -other is not. If both match results are ready, returns \tcode{true} only if: -\begin{itemize} -\item -\tcode{m1.empty() \&\& m2.empty()}, or - -\item -\tcode{!m1.empty() \&\& !m2.empty()}, and the following conditions are satisfied: -\begin{itemize} -\item -\tcode{m1.prefix() == m2.prefix()}, - -\item -\tcode{m1.size() == m2.size() \&\& equal(m1.begin(), m1.end(), m2.begin())}, and - -\item -\tcode{m1.suffix() == m2.suffix()}. -\end{itemize} -\end{itemize} -\begin{note} -The algorithm \tcode{equal} is defined in \ref{algorithms}. -\end{note} -\end{itemdescr} - -\rSec1[re.alg]{Regular expression algorithms} - -\rSec2[re.except]{Exceptions} -\pnum -The algorithms described in subclause~\ref{re.alg} may throw an exception -of type \tcode{regex_error}. If such an exception \tcode{e} is thrown, -\tcode{e.code()} shall return either \tcode{regex_constants::error_complexity} -or \tcode{regex_constants::error_stack}. - -\rSec2[re.alg.match]{\tcode{regex_match}} -\indexlibraryglobal{regex_match}% -\begin{itemdecl} -template - bool regex_match(BidirectionalIterator first, BidirectionalIterator last, - match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{BidirectionalIterator} models -\libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. - -\pnum -\effects -Determines whether there is a match between the -regular expression \tcode{e}, and all of the character -sequence \range{first}{last}. The parameter \tcode{flags} is -used to control how the expression is matched against the character -sequence. When determining if there is a match, only potential matches -that match the entire character sequence are considered. -Returns \tcode{true} if such a match exists, \tcode{false} -otherwise. -\begin{example} -\begin{codeblock} -std::regex re("Get|GetValue"); -std::cmatch m; -regex_search("GetValue", m, re); // returns \tcode{true}, and \tcode{m[0]} contains \tcode{"Get"} -regex_match ("GetValue", m, re); // returns \tcode{true}, and \tcode{m[0]} contains \tcode{"GetValue"} -regex_search("GetValues", m, re); // returns \tcode{true}, and \tcode{m[0]} contains \tcode{"Get"} -regex_match ("GetValues", m, re); // returns \tcode{false} -\end{codeblock} -\end{example} - -\pnum -\ensures -\tcode{m.ready() == true} in all cases. -If the function returns \tcode{false}, then the effect -on parameter \tcode{m} is unspecified except that \tcode{m.size()} -returns \tcode{0} and \tcode{m.empty()} returns \tcode{true}. -Otherwise the effects on parameter \tcode{m} are given in -\tref{re.alg.match}. -\end{itemdescr} - -\begin{longlibefftabvalue} - {Effects of \tcode{regex_match} algorithm} - {re.alg.match} -\tcode{m.size()} -& -\tcode{1 + e.mark_count()} -\\ \rowsep -\tcode{m.empty()} -& -\tcode{false} -\\ \rowsep -\tcode{m.prefix().first} -& -\tcode{first} -\\ \rowsep -\tcode{m.prefix().second} -& -\tcode{first} -\\ \rowsep -\tcode{m.prefix().matched} -& -\tcode{false} -\\ \rowsep -\tcode{m.suffix().first} -& -\tcode{last} -\\ \rowsep -\tcode{m.suffix().second} -& -\tcode{last} -\\ \rowsep -\tcode{m.suffix().matched} -& -\tcode{false} -\\ \rowsep -\tcode{m[0].first} -& -\tcode{first} -\\ \rowsep -\tcode{m[0].second} -& -\tcode{last} -\\ \rowsep -\tcode{m[0].matched} -& -\tcode{true} -\\ \rowsep -\tcode{m[n].first} -& -For all integers \tcode{0 < n < m.size()}, the start of the sequence that matched -sub-expression \tcode{n}. Alternatively, if sub-expression \tcode{n} did not participate -in the match, then \tcode{last}. -\\ \rowsep -\tcode{m[n].second} -& -For all integers \tcode{0 < n < m.size()}, the end of the sequence that matched -sub-expression \tcode{n}. Alternatively, if sub-expression \tcode{n} did not participate -in the match, then \tcode{last}. -\\ \rowsep -\tcode{m[n].matched} -& -For all integers \tcode{0 < n < m.size()}, \tcode{true} if sub-expression \tcode{n} participated in -the match, \tcode{false} otherwise. -\\ -\end{longlibefftabvalue} - -\indexlibraryglobal{regex_match}% -\begin{itemdecl} -template - bool regex_match(BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Behaves ``as if'' by constructing an instance of -\tcode{match_results what}, and then -returning the result of -\tcode{regex_match(first, last, what, e, flags)}. -\end{itemdescr} - -\indexlibraryglobal{regex_match}% -\begin{itemdecl} -template - bool regex_match(const charT* str, - match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_match(str, str + char_traits::length(str), m, e, flags)}. -\end{itemdescr} - -\indexlibraryglobal{regex_match}% -\begin{itemdecl} -template - bool regex_match(const basic_string& s, - match_results::const_iterator, - Allocator>& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_match(s.begin(), s.end(), m, e, flags)}. -\end{itemdescr} - -\indexlibraryglobal{regex_match}% -\begin{itemdecl} -template - bool regex_match(const charT* str, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_match(str, str + char_traits::length(str), e, flags)} -\end{itemdescr} - -\indexlibraryglobal{regex_match}% -\begin{itemdecl} -template - bool regex_match(const basic_string& s, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_match(s.begin(), s.end(), e, flags)}. -\end{itemdescr} - -\rSec2[re.alg.search]{\tcode{regex_search}} - -\indexlibraryglobal{regex_search}% -\begin{itemdecl} -template - bool regex_search(BidirectionalIterator first, BidirectionalIterator last, - match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{BidirectionalIterator} models -\libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. - -\pnum -\effects -Determines whether there is some sub-sequence within \range{first}{last} that matches -the regular expression \tcode{e}. The parameter \tcode{flags} is used to control how the -expression is matched against the character sequence. Returns \tcode{true} if such a sequence -exists, \tcode{false} otherwise. - -\pnum -\ensures -\tcode{m.ready() == true} in all cases. -If the function returns \tcode{false}, then the effect -on parameter \tcode{m} is unspecified except that \tcode{m.size()} -returns \tcode{0} and \tcode{m.empty()} returns \tcode{true}. Otherwise -the effects on parameter \tcode{m} are given in \tref{re.alg.search}. -\end{itemdescr} - -\begin{longlibefftabvalue} - {Effects of \tcode{regex_search} algorithm} - {re.alg.search} -\tcode{m.size()} -& -\tcode{1 + e.mark_count()} -\\ \rowsep -\tcode{m.empty()} -& -\tcode{false} -\\ \rowsep -\tcode{m.prefix().first} -& -\tcode{first} -\\ \rowsep -\tcode{m.prefix().second} -& -\tcode{m[0].first} -\\ \rowsep -\tcode{m.prefix().matched} -& -\tcode{m.prefix().first != m.prefix().second} -\\ \rowsep -\tcode{m.suffix().first} -& -\tcode{m[0].second} -\\ \rowsep -\tcode{m.suffix().second} -& -\tcode{last} -\\ \rowsep -\tcode{m.suffix().matched} -& -\tcode{m.suffix().first != m.suffix().second} -\\ \rowsep -\tcode{m[0].first} -& -The start of the sequence of characters that matched the regular expression -\\ \rowsep -\tcode{m[0].second} -& -The end of the sequence of characters that matched the regular expression -\\ \rowsep -\tcode{m[0].matched} -& -\tcode{true} -\\ \rowsep -\tcode{m[n].first} -& -For all integers \tcode{0 < n < m.size()}, the start of the sequence that -matched sub-expression \tcode{n}. Alternatively, if sub-expression \tcode{n} -did not participate in the match, then \tcode{last}. -\\ \rowsep -\tcode{m[n].second} -& -For all integers \tcode{0 < n < m.size()}, the end of the sequence that matched -sub-expression \tcode{n}. Alternatively, if sub-expression \tcode{n} did not -participate in the match, then \tcode{last}. -\\ \rowsep -\tcode{m[n].matched} -& -For all integers \tcode{0 < n < m.size()}, \tcode{true} if sub-expression \tcode{n} -participated in the match, \tcode{false} otherwise. -\\ -\end{longlibefftabvalue} - -\indexlibraryglobal{regex_search}% -\begin{itemdecl} -template - bool regex_search(const charT* str, match_results& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_search(str, str + char_traits::length(str), m, e, flags)}. -\end{itemdescr} - -\indexlibraryglobal{regex_search}% -\begin{itemdecl} -template - bool regex_search(const basic_string& s, - match_results::const_iterator, - Allocator>& m, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_search(s.begin(), s.end(), m, e, flags)}. -\end{itemdescr} - -\indexlibraryglobal{regex_search}% -\begin{itemdecl} -template - bool regex_search(BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Behaves ``as if'' by constructing an object \tcode{what} -of type \tcode{match_results} and returning -\tcode{regex_search(first, last, what, e, flags)}. -\end{itemdescr} - -\indexlibraryglobal{regex_search}% -\begin{itemdecl} -template - bool regex_search(const charT* str, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_search(str, str + char_traits::length(str), e, flags)}. -\end{itemdescr} - -\indexlibraryglobal{regex_search}% -\begin{itemdecl} -template - bool regex_search(const basic_string& s, - const basic_regex& e, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{regex_search(s.begin(), s.end(), e, flags)}. -\end{itemdescr} - -\rSec2[re.alg.replace]{\tcode{regex_replace}} - -\indexlibraryglobal{regex_replace}% -\begin{itemdecl} -template - OutputIterator - regex_replace(OutputIterator out, - BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); -template - OutputIterator - regex_replace(OutputIterator out, - BidirectionalIterator first, BidirectionalIterator last, - const basic_regex& e, - const charT* fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\indexlibraryglobal{format_no_copy}% -\indexlibraryglobal{format_first_only}% -\effects -Constructs a \tcode{regex_iterator} object \tcode{i} -as if by -\begin{codeblock} -regex_iterator i(first, last, e, flags) -\end{codeblock} -and uses \tcode{i} to enumerate through all -of the matches \tcode{m} of type \tcode{match_results} -that occur within the sequence \range{first}{last}. -If no such -matches are found and -\tcode{!(flags \& regex_constants::format_no_copy)}, then calls -\begin{codeblock} -out = copy(first, last, out) -\end{codeblock} -If any matches are found then, for each such match: -\begin{itemize} -\item -If \tcode{!(flags \& regex_constants::format_no_copy)}, calls -\begin{codeblock} -out = copy(m.prefix().first, m.prefix().second, out) -\end{codeblock} -\item -Then calls -\begin{codeblock} -out = m.format(out, fmt, flags) -\end{codeblock} -for the first form of the function and -\begin{codeblock} -out = m.format(out, fmt, fmt + char_traits::length(fmt), flags) -\end{codeblock} -for the second. -\end{itemize} -Finally, if such a match -is found and \tcode{!(flags \& regex_constants::format_no_copy)}, -calls -\begin{codeblock} -out = copy(last_m.suffix().first, last_m.suffix().second, out) -\end{codeblock} -where \tcode{last_m} is a copy of the last match -found. If \tcode{flags \& regex_constants::format_first_only} -is nonzero, then only the first match found is replaced. - -\pnum -\returns -\tcode{out}. -\end{itemdescr} - -\indexlibraryglobal{regex_replace}% -\begin{itemdecl} -template - basic_string - regex_replace(const basic_string& s, - const basic_regex& e, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); -template - basic_string - regex_replace(const basic_string& s, - const basic_regex& e, - const charT* fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs an empty string \tcode{result} of -type \tcode{basic_string} and calls: -\begin{codeblock} -regex_replace(back_inserter(result), s.begin(), s.end(), e, fmt, flags); -\end{codeblock} - -\pnum -\returns -\tcode{result}. -\end{itemdescr} - -\indexlibraryglobal{regex_replace}% -\begin{itemdecl} -template - basic_string - regex_replace(const charT* s, - const basic_regex& e, - const basic_string& fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); -template - basic_string - regex_replace(const charT* s, - const basic_regex& e, - const charT* fmt, - regex_constants::match_flag_type flags = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs an empty string \tcode{result} of -type \tcode{basic_string} and calls: -\begin{codeblock} -regex_replace(back_inserter(result), s, s + char_traits::length(s), e, fmt, flags); -\end{codeblock} - -\pnum -\returns -\tcode{result}. -\end{itemdescr} - -\rSec1[re.iter]{Regular expression iterators} - -\rSec2[re.regiter]{Class template \tcode{regex_iterator}} - -\rSec3[re.regiter.general]{General} -\pnum -\indexlibraryglobal{regex_iterator}% -\indexlibraryglobal{match_results}% -The class template \tcode{regex_iterator} is an iterator adaptor. -It represents a new view of an existing iterator sequence, by -enumerating all the occurrences of a regular expression within that -sequence. A \tcode{regex_iterator} uses \tcode{regex_search} to find successive -regular expression matches within the sequence from which it was -constructed. After the iterator is constructed, and every time \tcode{operator++} is -used, the iterator finds and stores a value of -\tcode{match_results}. If the end of the sequence is -reached (\tcode{regex_search} returns \tcode{false}), the iterator becomes equal to -the end-of-sequence iterator value. The default constructor -constructs an end-of-sequence iterator object, -which is the only legitimate iterator to be used for the end -condition. The result of \tcode{operator*} on an end-of-sequence iterator is not -defined. For any other iterator value a const -\tcode{match_results\&} is returned. The result of -\tcode{operator->} on an end-of-sequence iterator is not defined. For any other -iterator value a \tcode{const match_results*} is -returned. It is impossible to store things into \tcode{regex_iterator}s. Two -end-of-sequence iterators are always equal. An end-of-sequence -iterator is not equal to a non-end-of-sequence iterator. Two -non-end-of-sequence iterators are equal when they are constructed from -the same arguments. - -\begin{codeblock} -namespace std { - template::value_type, - class traits = regex_traits> - class regex_iterator { - public: - using regex_type = basic_regex; - using iterator_category = forward_iterator_tag; - using iterator_concept = input_iterator_tag; - using value_type = match_results; - using difference_type = ptrdiff_t; - using pointer = const value_type*; - using reference = const value_type&; - - regex_iterator(); - regex_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - regex_constants::match_flag_type m = regex_constants::match_default); - regex_iterator(BidirectionalIterator, BidirectionalIterator, - const regex_type&&, - regex_constants::match_flag_type = regex_constants::match_default) = delete; - regex_iterator(const regex_iterator&); - regex_iterator& operator=(const regex_iterator&); - bool operator==(const regex_iterator&) const; - bool operator==(default_sentinel_t) const { return *this == regex_iterator(); } - const value_type& operator*() const; - const value_type* operator->() const; - regex_iterator& operator++(); - regex_iterator operator++(int); - - private: - BidirectionalIterator begin; // \expos - BidirectionalIterator end; // \expos - const regex_type* pregex; // \expos - regex_constants::match_flag_type flags; // \expos - match_results match; // \expos - }; -} -\end{codeblock} - -\pnum -An object of type \tcode{regex_iterator} that is not an end-of-sequence iterator -holds a \textit{zero-length match} if \tcode{match[0].matched == true} and -\tcode{match[0].first == match[0].second}. -\begin{note} -For -example, this can occur when the part of the regular expression that -matched consists only of an assertion (such as \verb|'^'|, \verb|'$'|, -\tcode{'$\backslash$b'}, \tcode{'$\backslash$B'}). -\end{note} - -\rSec3[re.regiter.cnstr]{Constructors} - -\indexlibraryctor{regex_iterator}% -\begin{itemdecl} -regex_iterator(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs an end-of-sequence iterator. -\end{itemdescr} - -\indexlibraryctor{regex_iterator}% -\begin{itemdecl} -regex_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - regex_constants::match_flag_type m = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{begin} and \tcode{end} to -\tcode{a} and \tcode{b}, respectively, sets -\tcode{pregex} to \tcode{addressof(re)}, sets \tcode{flags} to -\tcode{m}, then calls \tcode{regex_search(begin, end, match, *pregex, flags)}. If this -call returns \tcode{false} the constructor sets \tcode{*this} to the end-of-sequence -iterator. -\end{itemdescr} - -\rSec3[re.regiter.comp]{Comparisons} - -\indexlibrarymember{regex_iterator}{operator==}% -\begin{itemdecl} -bool operator==(const regex_iterator& right) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if \tcode{*this} and \tcode{right} are both end-of-sequence -iterators or if the following conditions all hold: -\begin{itemize} -\item \tcode{begin == right.begin}, -\item \tcode{end == right.end}, -\item \tcode{pregex == right.pregex}, -\item \tcode{flags == right.flags}, and -\item \tcode{match[0] == right.match[0]}; -\end{itemize} -otherwise \tcode{false}. -\end{itemdescr} - -\rSec3[re.regiter.deref]{Indirection} - -\indexlibrarymember{regex_iterator}{operator*}% -\begin{itemdecl} -const value_type& operator*() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{match}. -\end{itemdescr} - -\indexlibrarymember{operator->}{regex_iterator}% -\begin{itemdecl} -const value_type* operator->() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{addressof(match)}. -\end{itemdescr} - -\rSec3[re.regiter.incr]{Increment} - -\indexlibrarymember{regex_iterator}{operator++}% -\indexlibrary{\idxcode{regex_iterator}!increment}% -\begin{itemdecl} -regex_iterator& operator++(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a local variable \tcode{start} of type \tcode{BidirectionalIterator} and -initializes it with the value of \tcode{match[0].second}. - -\pnum -If the iterator holds a zero-length match and \tcode{start == end} the operator -sets \tcode{*this} to the end-of-sequence iterator and returns \tcode{*this}. - -\pnum -\indexlibraryglobal{match_not_null}% -\indexlibraryglobal{match_continuous}% -Otherwise, if the iterator holds a zero-length match, the operator calls: -\begin{codeblock} -regex_search(start, end, match, *pregex, - flags | regex_constants::match_not_null | regex_constants::match_continuous) -\end{codeblock} -If the call returns \tcode{true} the operator -returns \tcode{*this}. Otherwise the operator increments \tcode{start} and continues as if -the most recent match was not a zero-length match. - -\pnum -\indexlibraryglobal{match_prev_avail}% -If the most recent match was not a zero-length match, the operator sets -\tcode{flags} to \tcode{flags | regex_constants::match_prev_avail} and -calls \tcode{regex_search(start, end, match, *pregex, flags)}. If the call returns -\tcode{false} the iterator sets \tcode{*this} to the end-of-sequence iterator. The -iterator then returns \tcode{*this}. - -\pnum -In all cases in which the call to \tcode{regex_search} returns \tcode{true}, -\tcode{match.prefix().first} shall be equal to the previous value of -\tcode{match[0].second}, and for each index \tcode{i} in the half-open range -\tcode{[0, match.size())} for which \tcode{match[i].matched} is \tcode{true}, -\tcode{match.position(i)} -shall return \tcode{distance(begin, match[i].\brk{}first)}. - -\pnum -\begin{note} -This means that \tcode{match.position(i)} gives the -offset from the beginning of the target sequence, which is often not -the same as the offset from the sequence passed in the call -to \tcode{regex_search}. -\end{note} - -\pnum -It is unspecified how the implementation makes these adjustments. - -\pnum -\begin{note} -This means that an implementation can call an -implementation-specific search function, in which case a program-defined -specialization of \tcode{regex_search} will not be -called. -\end{note} -\end{itemdescr} - -\indexlibrarymember{regex_iterator}{operator++}% -\begin{itemdecl} -regex_iterator operator++(int); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -As if by: -\begin{codeblock} -regex_iterator tmp = *this; -++(*this); -return tmp; -\end{codeblock} -\end{itemdescr} - -\rSec2[re.tokiter]{Class template \tcode{regex_token_iterator}} - -\rSec3[re.tokiter.general]{General} - -\pnum -\indexlibraryglobal{regex_token_iterator}% -The class template \tcode{regex_token_iterator} is an iterator adaptor; that -is to say it represents a new view of an existing iterator sequence, -by enumerating all the occurrences of a regular expression within that -sequence, and presenting one or more sub-expressions for each match -found. Each position enumerated by the iterator is a \tcode{sub_match} class -template instance that represents what matched a particular sub-expression -within the regular expression. - -\pnum -When class \tcode{regex_token_iterator} is used to enumerate a -single sub-expression with index $-1$ the iterator performs field -splitting: that is to say it enumerates one sub-expression for each section of -the character container sequence that does not match the regular -expression specified. - -\pnum -\indexlibraryglobal{match_results}% -After it is constructed, the iterator finds and stores a value -\tcode{regex_iterator position} -and sets the internal count \tcode{N} to zero. It also maintains a sequence -\tcode{subs} which contains a list of the sub-expressions which will be -enumerated. Every time \tcode{operator++} is used -the count \tcode{N} is incremented; if \tcode{N} exceeds or equals \tcode{subs.size()}, -then the iterator increments member \tcode{position} -and sets count \tcode{N} to zero. - -\pnum -If the end of sequence is reached (\tcode{position} is equal to the end of -sequence iterator), the iterator becomes equal to the end-of-sequence -iterator value, unless the sub-expression being enumerated has index $-1$, -in which case the iterator enumerates one last sub-expression that contains -all the characters from the end of the last regular expression match to the -end of the input sequence being enumerated, provided that this would not be an -empty sub-expression. - -\pnum -\indexlibrary{\idxcode{regex_token_iterator}!end-of-sequence}% -The default constructor constructs -an end-of-sequence iterator object, which is the only legitimate -iterator to be used for the end condition. The result of \tcode{operator*} on -an end-of-sequence iterator is not defined. For any other iterator value a -\tcode{const sub_match\&} is returned. -The result of \tcode{operator->} on an end-of-sequence iterator -is not defined. For any other iterator value a \tcode{const -sub_match*} is returned. - -\pnum -\indexlibrarymember{regex_token_iterator}{operator==}% -It is impossible to store things -into \tcode{regex_token_iterator}s. Two end-of-sequence iterators are always -equal. An end-of-sequence iterator is not equal to a -non-end-of-sequence iterator. Two non-end-of-sequence iterators are -equal when they are constructed from the same arguments. - -\begin{codeblock} -namespace std { - template::value_type, - class traits = regex_traits> - class regex_token_iterator { - public: - using regex_type = basic_regex; - using iterator_category = forward_iterator_tag; - using iterator_concept = input_iterator_tag; - using value_type = sub_match; - using difference_type = ptrdiff_t; - using pointer = const value_type*; - using reference = const value_type&; - - regex_token_iterator(); - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - int submatch = 0, - regex_constants::match_flag_type m = - regex_constants::match_default); - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - const vector& submatches, - regex_constants::match_flag_type m = - regex_constants::match_default); - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - initializer_list submatches, - regex_constants::match_flag_type m = - regex_constants::match_default); - template - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - const int (&submatches)[N], - regex_constants::match_flag_type m = - regex_constants::match_default); - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type&& re, - int submatch = 0, - regex_constants::match_flag_type m = - regex_constants::match_default) = delete; - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type&& re, - const vector& submatches, - regex_constants::match_flag_type m = - regex_constants::match_default) = delete; - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type&& re, - initializer_list submatches, - regex_constants::match_flag_type m = - regex_constants::match_default) = delete; - template - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type&& re, - const int (&submatches)[N], - regex_constants::match_flag_type m = - regex_constants::match_default) = delete; - regex_token_iterator(const regex_token_iterator&); - regex_token_iterator& operator=(const regex_token_iterator&); - bool operator==(const regex_token_iterator&) const; - bool operator==(default_sentinel_t) const { return *this == regex_token_iterator(); } - const value_type& operator*() const; - const value_type* operator->() const; - regex_token_iterator& operator++(); - regex_token_iterator operator++(int); - - private: - using position_iterator = - regex_iterator; // \expos - position_iterator position; // \expos - const value_type* result; // \expos - value_type suffix; // \expos - size_t N; // \expos - vector subs; // \expos - }; -} -\end{codeblock} - -\pnum -A \textit{suffix iterator} is a \tcode{regex_token_iterator} object -that points to a final sequence of characters at -the end of the target sequence. In a suffix iterator the -member \tcode{result} holds a pointer to the data -member \tcode{suffix}, the value of the member \tcode{suffix.match} -is \tcode{true}, \tcode{suffix.first} points to the beginning of the -final sequence, and \tcode{suffix.second} points to the end of the -final sequence. - -\pnum -\begin{note} -For a suffix iterator, data -member \tcode{suffix.first} is the same as the end of the last match -found, and \tcode{suffix\brk.second} is the same as the end of the target -sequence. -\end{note} - -\pnum -The \textit{current match} is \tcode{(*position).prefix()} if \tcode{subs[N] == -1}, or -\tcode{(*position)[subs[N]]} for any other value of \tcode{subs[N]}. - -\rSec3[re.tokiter.cnstr]{Constructors} - -\indexlibraryctor{regex_token_iterator}% -\begin{itemdecl} -regex_token_iterator(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs the end-of-sequence iterator. -\end{itemdescr} - -\indexlibraryctor{regex_token_iterator}% -\begin{itemdecl} -regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - int submatch = 0, - regex_constants::match_flag_type m = regex_constants::match_default); - -regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - const vector& submatches, - regex_constants::match_flag_type m = regex_constants::match_default); - -regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - initializer_list submatches, - regex_constants::match_flag_type m = regex_constants::match_default); - -template - regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, - const regex_type& re, - const int (&submatches)[N], - regex_constants::match_flag_type m = regex_constants::match_default); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -Each of the initialization values of \tcode{submatches} is \tcode{>= -1}. - -\pnum -\effects -The first constructor initializes the member \tcode{subs} to hold the single -value \tcode{submatch}. -The second, third, and fourth constructors -initialize the member \tcode{subs} to hold a copy of the sequence of integer values -pointed to by the iterator range -\range{begin(submatches)}{end(submatches)}. - -\pnum -Each constructor then sets \tcode{N} to 0, and \tcode{position} to -\tcode{position_iterator(a, b, re, m)}. If \tcode{position} is not an -end-of-sequence iterator the constructor sets \tcode{result} to the -address of the current match. Otherwise if any of the values stored -in \tcode{subs} is equal to $-1$ the constructor sets \tcode{*this} to a suffix -iterator that points to the range \range{a}{b}, otherwise the constructor -sets \tcode{*this} to an end-of-sequence iterator. -\end{itemdescr} - -\rSec3[re.tokiter.comp]{Comparisons} - -\indexlibrarymember{regex_token_iterator}{operator==}% -\begin{itemdecl} -bool operator==(const regex_token_iterator& right) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if \tcode{*this} and \tcode{right} are both end-of-sequence iterators, -or if \tcode{*this} and \tcode{right} are both suffix iterators and \tcode{suffix == right.suffix}; -otherwise returns \tcode{false} if \tcode{*this} or \tcode{right} is an end-of-sequence -iterator or a suffix iterator. Otherwise returns \tcode{true} if \tcode{position == right.position}, -\tcode{N == right.N}, and \tcode{subs == right.subs}. Otherwise returns \tcode{false}. -\end{itemdescr} - -\rSec3[re.tokiter.deref]{Indirection} - -\indexlibrarymember{regex_token_iterator}{operator*}% -\begin{itemdecl} -const value_type& operator*() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{*result}. -\end{itemdescr} - -\indexlibrarymember{operator->}{regex_token_iterator}% -\begin{itemdecl} -const value_type* operator->() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{result}. -\end{itemdescr} - - -\rSec3[re.tokiter.incr]{Increment} - -\indexlibrarymember{regex_token_iterator}{operator++}% -\begin{itemdecl} -regex_token_iterator& operator++(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a local variable \tcode{prev} of -type \tcode{position_iterator}, initialized with the value -of \tcode{position}. - -\pnum -If \tcode{*this} is a suffix iterator, sets \tcode{*this} to an -end-of-sequence iterator. - -\pnum -Otherwise, if \tcode{N + 1 < subs.size()}, increments \tcode{N} and -sets \tcode{result} to the address of the current match. - -\pnum -Otherwise, sets \tcode{N} to 0 and -increments \tcode{position}. If \tcode{position} is not an -end-of-sequence iterator the operator sets \tcode{result} to the -address of the current match. - -\pnum -Otherwise, if any of the values stored in \tcode{subs} is equal to $-1$ and -\tcode{prev->suffix().length()} is not 0 the operator sets \tcode{*this} to a -suffix iterator that points to the range \range{prev->suffix().first}{prev->suffix().second}. - -\pnum -Otherwise, sets \tcode{*this} to an end-of-sequence iterator. - -\pnum -\returns -\tcode{*this} -\end{itemdescr} - -\indexlibrarymember{regex_token_iterator}{operator++}% -\begin{itemdecl} -regex_token_iterator& operator++(int); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a copy \tcode{tmp} of \tcode{*this}, then calls \tcode{++(*this)}. - -\pnum -\returns -\tcode{tmp}. -\end{itemdescr} - -\rSec1[re.grammar]{Modified ECMAScript regular expression grammar} -\indextext{regular expression!grammar}% -\indextext{grammar!regular expression}% - -\pnum -\indexlibraryglobal{basic_regex}% -\indextext{ECMAScript}% -The regular expression grammar recognized by -\tcode{basic_regex} objects constructed with the ECMAScript -flag is that specified by ECMA-262, except as specified below. - -\pnum -\indexlibraryglobal{locale}% -\indextext{regular expression traits}% -Objects of type specialization of \tcode{basic_regex} store within themselves a -default-constructed instance of their \tcode{traits} template parameter, henceforth -referred to as \tcode{traits_inst}. This \tcode{traits_inst} object is used to support localization -of the regular expression; \tcode{basic_regex} member functions shall not call -any locale dependent C or \Cpp{} API, including the formatted string input functions. -Instead they shall call the appropriate traits member function to achieve the required effect. - -\pnum -The following productions within the ECMAScript grammar are modified as follows: - -\begin{ncrebnf} -\renontermdef{ClassAtom}\br - \terminal{-}\br - ClassAtomNoDash\br - ClassAtomExClass\br - ClassAtomCollatingElement\br - ClassAtomEquivalence -\end{ncrebnf} - -\begin{ncrebnf} -\renontermdef{IdentityEscape}\br - SourceCharacter \textnormal{\textbf{but not}} \terminal{c} -\end{ncrebnf} - -\pnum -The following new productions are then added: - -\begin{ncrebnf} -\renontermdef{ClassAtomExClass}\br - \terminal{[:} ClassName \terminal{:]} -\end{ncrebnf} - -\begin{ncrebnf} -\renontermdef{ClassAtomCollatingElement}\br - \terminal{[.} ClassName \terminal{.]} -\end{ncrebnf} - -\begin{ncrebnf} -\renontermdef{ClassAtomEquivalence}\br - \terminal{[=} ClassName \terminal{=]} -\end{ncrebnf} - -\begin{ncrebnf} -\renontermdef{ClassName}\br - ClassNameCharacter\br - ClassNameCharacter ClassName -\end{ncrebnf} - -\begin{ncrebnf} -\renontermdef{ClassNameCharacter}\br - SourceCharacter \textnormal{\textbf{but not one of}} \terminal{.} \textnormal{\textbf{or}} \terminal{=} \textnormal{\textbf{or}} \terminal{:} -\end{ncrebnf} - -\pnum -The productions \regrammarterm{ClassAtomExClass}, \regrammarterm{ClassAtomCollatingElement} -and \regrammarterm{ClassAtomEquivalence} provide functionality -equivalent to that of the same features in regular expressions in POSIX. - -\pnum -The regular expression grammar may be modified by -any \tcode{regex_constants::syntax_option_type} flags specified when -constructing an object of type specialization of \tcode{basic_regex} -according to the rules in \tref{re.synopt}. - -\pnum -A \regrammarterm{ClassName} production, when used in \regrammarterm{ClassAtomExClass}, -is not valid if \tcode{traits_inst.lookup_classname} returns zero for -that name. The names recognized as valid \regrammarterm{ClassName}s are -determined by the type of the traits class, but at least the following -names shall be recognized: -\tcode{alnum}, \tcode{alpha}, \tcode{blank}, \tcode{cntrl}, \tcode{digit}, -\tcode{graph}, \tcode{lower}, \tcode{print}, \tcode{punct}, \tcode{space}, -\tcode{upper}, \tcode{xdigit}, \tcode{d}, \tcode{s}, \tcode{w}. -In addition the following expressions shall be equivalent: - -\begin{codeblock} -\d @\textnormal{and}@ [[:digit:]] - -\D @\textnormal{and}@ [^[:digit:]] - -\s @\textnormal{and}@ [[:space:]] - -\S @\textnormal{and}@ [^[:space:]] - -\w @\textnormal{and}@ [_[:alnum:]] - -\W @\textnormal{and}@ [^_[:alnum:]] -\end{codeblock} - -\pnum -\indexlibrary{regular expression traits!\idxcode{lookup_collatename}}% -\indexlibrary{\idxcode{lookup_collatename}!regular expression traits}% -A \regrammarterm{ClassName} production when used in -a \regrammarterm{ClassAtomCollatingElement} production is not valid -if the value returned by \tcode{traits_inst.lookup_collatename} for -that name is an empty string. - -\pnum -\indexlibrary{regular expression traits!\idxcode{isctype}}% -\indexlibrary{\idxcode{isctype}!regular expression traits}% -\indexlibrary{regular expression traits!\idxcode{lookup_classname}}% -\indexlibrary{\idxcode{lookup_classname}!regular expression traits}% -The results from multiple calls -to \tcode{traits_inst.lookup_classname} can be bitwise \logop{or}'ed -together and subsequently passed to \tcode{traits_inst.isctype}. - -\pnum -A \regrammarterm{ClassName} production when used in -a \regrammarterm{ClassAtomEquivalence} production is not valid if the value -returned by \tcode{traits_inst.lookup_collatename} for that name is an -empty string or if the value returned by \tcode{traits_inst\brk.transform_primary} -for the result of the call to \tcode{traits_inst.lookup_collatename} -is an empty string. - -\pnum -\indexlibraryglobal{regex_error}% -When the sequence of characters being transformed to a finite state -machine contains an invalid class name the translator shall throw an -exception object of type \tcode{regex_error}. - -\pnum -\indexlibraryglobal{regex_error}% -If the \textit{CV} of a \textit{UnicodeEscapeSequence} is greater than the largest -value that can be held in an object of type \tcode{charT} the translator shall -throw an exception object of type \tcode{regex_error}. -\begin{note} -This means that values of the form \tcode{"uxxxx"} that do not fit in -a character are invalid. -\end{note} - -\pnum -Where the regular expression grammar requires the conversion of a sequence of characters -to an integral value, this is accomplished by calling \tcode{traits_inst.value}. - -\pnum -\indexlibraryglobal{match_flag_type}% -The behavior of the internal finite state machine representation when used to match a -sequence of characters is as described in ECMA-262. -The behavior is modified according -to any \tcode{match_flag_type} flags\iref{re.matchflag} specified when using the regular expression -object in one of the regular expression algorithms\iref{re.alg}. The behavior is also -localized by interaction with the traits class template parameter as follows: -\begin{itemize} -\item During matching of a regular expression finite state machine -against a sequence of characters, two characters \tcode{c} -and \tcode{d} are compared using the following rules: -\begin{itemize} -\item if \tcode{(flags() \& regex_constants::icase)} the two characters are equal -if \tcode{traits_inst.trans\-late_nocase(c) == traits_inst.translate_nocase(d)}; -\item otherwise, if \tcode{flags() \& regex_constants::collate} the -two characters are equal if -\tcode{traits_inst\brk.translate(c) == traits_inst\brk.translate(d)}; -\indexlibrarymember{syntax_option_type}{collate}% -\item otherwise, the two characters are equal if \tcode{c == d}. -\end{itemize} - -\item During matching of a regular expression finite state machine -against a sequence of characters, comparison of a collating element -range \tcode{c1-c2} against a character \tcode{c} is -conducted as follows: if \tcode{flags() \& regex_constants::collate} -is \tcode{false} then the character \tcode{c} is matched if \tcode{c1 -<= c \&\& c <= c2}, otherwise \tcode{c} is matched in -accordance with the following algorithm: - -\begin{codeblock} -string_type str1 = string_type(1, - flags() & icase ? - traits_inst.translate_nocase(c1) : traits_inst.translate(c1)); -string_type str2 = string_type(1, - flags() & icase ? - traits_inst.translate_nocase(c2) : traits_inst.translate(c2)); -string_type str = string_type(1, - flags() & icase ? - traits_inst.translate_nocase(c) : traits_inst.translate(c)); -return traits_inst.transform(str1.begin(), str1.end()) - <= traits_inst.transform(str.begin(), str.end()) - && traits_inst.transform(str.begin(), str.end()) - <= traits_inst.transform(str2.begin(), str2.end()); -\end{codeblock} - -\item During matching of a regular expression finite state machine against a sequence of -characters, testing whether a collating element is a member of a primary equivalence -class is conducted by first converting the collating element and the equivalence -class to sort keys using \tcode{traits::transform_primary}, and then comparing the sort -keys for equality. -\indextext{regular expression traits!\idxcode{transform_primary}}% -\indextext{transform_primary@\tcode{transform_primary}!regular expression traits}% - -\item During matching of a regular expression finite state machine against a sequence -of characters, a character \tcode{c} is a member of a character class designated by an -iterator range \range{first}{last} if -\tcode{traits_inst.isctype(c, traits_inst.lookup_classname(first, last, flags() \& icase))} is \tcode{true}. -\end{itemize} -\xref ECMA-262 15.10 -\indextext{regular expression|)} diff --git a/source/statements.tex b/source/statements.tex index 4c8bef837e..ba75c744d2 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -1,5 +1,5 @@ %!TEX root = std.tex -\rSec0[stmt.stmt]{Statements}% +\rSec0[stmt]{Statements}% \indextext{statement|(} \gramSec[gram.stmt]{Statements} @@ -9,7 +9,7 @@ \rSec1[stmt.pre]{Preamble} \pnum -Except as indicated, statements are executed in sequence. +Except as indicated, statements are executed in sequence\iref{intro.execution}. \begin{bnf} \nontermdef{statement}\br @@ -19,6 +19,7 @@ \opt{attribute-specifier-seq} selection-statement\br \opt{attribute-specifier-seq} iteration-statement\br \opt{attribute-specifier-seq} jump-statement\br + \opt{attribute-specifier-seq} assertion-statement\br declaration-statement\br \opt{attribute-specifier-seq} try-block \end{bnf} @@ -33,7 +34,8 @@ \begin{bnf} \nontermdef{condition}\br expression\br - \opt{attribute-specifier-seq} decl-specifier-seq declarator brace-or-equal-initializer + \opt{attribute-specifier-seq} decl-specifier-seq declarator brace-or-equal-initializer\br + structured-binding-declaration initializer \end{bnf} The optional \grammarterm{attribute-specifier-seq} appertains to the respective statement. @@ -86,8 +88,12 @@ The rules for \grammarterm{condition}{s} apply both to \grammarterm{selection-statement}{s}\iref{stmt.select} and to the \keyword{for} and \keyword{while} statements\iref{stmt.iter}. -A \grammarterm{condition} that is not an \grammarterm{expression} is a -declaration\iref{dcl.dcl}. +If a \grammarterm{structured-binding-declaration} +appears in a \grammarterm{condition}, +the \grammarterm{condition} is a structured binding declaration\iref{dcl.pre}. +A \grammarterm{condition} that is +neither an \grammarterm{expression} nor a structured binding declaration +is a declaration\iref{dcl}. The \grammarterm{declarator} shall not specify a function or an array. The \grammarterm{decl-specifier-seq} shall not define a class or enumeration. If the \keyword{auto} \grammarterm{type-specifier} appears in @@ -95,9 +101,16 @@ the type of the identifier being declared is deduced from the initializer as described in~\ref{dcl.spec.auto}. \pnum -The value of a \grammarterm{condition} that is an initialized declaration +The \defnadj{decision}{variable} of a \grammarterm{condition} +that is neither an \grammarterm{expression} nor a structured binding declaration +is the declared variable. +The decision variable of a \grammarterm{condition} +that is a structured binding declaration is specified in \ref{dcl.struct.bind}. + +\pnum +The value of a \grammarterm{condition} that is not an \grammarterm{expression} in a statement other than a \keyword{switch} statement is the value of the -declared variable +decision variable contextually converted to \tcode{bool}\iref{conv}. If that conversion is ill-formed, the program is ill-formed. @@ -116,7 +129,10 @@ it is interpreted as the latter. \pnum -In the \grammarterm{decl-specifier-seq} of a \grammarterm{condition}, each +In the \grammarterm{decl-specifier-seq} of a \grammarterm{condition}, +including that of any \grammarterm{structured-binding-declaration} of +the \grammarterm{condition}, +each \grammarterm{decl-specifier} shall be either a \grammarterm{type-specifier} or \keyword{constexpr}. @@ -188,7 +204,7 @@ side effects from an expression statement are completed before the next statement is executed. \indextext{statement!empty}% -An expression statement with the expression missing is called +An expression statement with the \grammarterm{expression} missing is called a \defnadj{null}{statement}. \begin{note} Most statements are expression statements --- usually assignments or @@ -211,14 +227,12 @@ \begin{bnf} \nontermdef{statement-seq}\br - statement\br - statement-seq statement + statement \opt{statement-seq} \end{bnf} \begin{bnf} \nontermdef{label-seq}\br - label\br - label-seq label + label \opt{label-seq} \end{bnf} A label at the end of a \grammarterm{compound-statement} @@ -267,7 +281,7 @@ \indextext{statement!\idxcode{if}} \pnum -If the condition\iref{stmt.pre} yields \tcode{true} the first +If the condition\iref{stmt.pre} yields \tcode{true}, the first substatement is executed. If the \keyword{else} part of the selection statement is present and the condition yields \tcode{false}, the second substatement is executed. If the first substatement is reached via a @@ -408,10 +422,9 @@ several statements depending on the value of a condition. \pnum -The value of a \grammarterm{condition} -that is an initialized declaration -is the value of the declared variable, -or the value of the \grammarterm{expression} otherwise. +If the \grammarterm{condition} is an \grammarterm{expression}, +the value of the condition is the value of the \grammarterm{expression}; +otherwise, it is the value of the decision variable. The value of the condition shall be of integral type, enumeration type, or class type. If of class type, the condition is contextually implicitly converted\iref{conv} to @@ -509,7 +522,7 @@ \begin{bnf} \nontermdef{for-range-declaration}\br \opt{attribute-specifier-seq} decl-specifier-seq declarator\br - \opt{attribute-specifier-seq} decl-specifier-seq \opt{ref-qualifier} \terminal{[} identifier-list \terminal{]} + structured-binding-declaration \end{bnf} \begin{bnf} @@ -546,11 +559,42 @@ Thus after the \keyword{while} statement, \tcode{i} is no longer in scope. \end{example} +\pnum +A \defnadj{trivially empty}{iteration statement} is +an iteration statement matching one of the following forms: +\begin{itemize} +\item \tcode{while (} \grammarterm{expression} \tcode{) ;} +\item \tcode{while (} \grammarterm{expression} \tcode{) \{ \}} +\item \tcode{do ; while (} \grammarterm{expression} \tcode{) ;} +\item \tcode{do \{ \} while (} \grammarterm{expression} \tcode{) ;} +\item \tcode{for (} \grammarterm{init-statement} \opt{\grammarterm{expression}} \tcode{; ) ;} +\item \tcode{for (} \grammarterm{init-statement} \opt{\grammarterm{expression}} \tcode{; ) \{ \}} +\end{itemize} +The \defnadj{controlling}{expression} of a trivially empty iteration statement +is the \grammarterm{expression} of +a \tcode{while}, \tcode{do}, or \tcode{for} statement +(or \tcode{true}, if the \tcode{for} statement has no \grammarterm{expression}). +A \defnadj{trivial infinite}{loop} is a trivially empty iteration statement +for which the converted controlling expression is a constant expression, +when interpreted as a \grammarterm{constant-expression}\iref{expr.const}, and +evaluates to \tcode{true}. +The \grammarterm{statement} of a trivial infinite loop is replaced with +a call to the function \tcode{std::this_thread::yield}\iref{thread.thread.this}; +it is \impldef{whether freestanding implementations replace the \grammarterm{statement} +of a trivial infinite loop with a call to the function \tcode{std::this_thread::yield}} +whether this replacement occurs on freestanding implementations. +\begin{note} +In a freestanding environment, +concurrent forward progress is not guaranteed; +such systems therefore require explicit cooperation. +A call to yield can add implicit cooperation where none is otherwise intended. +\end{note} + \rSec2[stmt.while]{The \keyword{while} statement}% \indextext{statement!\idxcode{while}} \pnum -In the \keyword{while} statement the substatement is executed repeatedly +In the \keyword{while} statement, the substatement is executed repeatedly until the value of the condition\iref{stmt.pre} becomes \tcode{false}. The test takes place before each execution of the substatement. @@ -598,7 +642,7 @@ if that conversion is ill-formed, the program is ill-formed. \pnum -In the \keyword{do} statement the substatement is executed repeatedly +In the \keyword{do} statement, the substatement is executed repeatedly until the value of the expression becomes \tcode{false}. The test takes place after each execution of the statement. @@ -677,15 +721,15 @@ \exposid{begin-expr} and \exposid{end-expr} are determined as follows: \begin{itemize} -\item if the \grammarterm{for-range-initializer} is an expression of +\item if the type of \exposid{range} is a reference to an array type \tcode{R}, \exposid{begin-expr} and \exposid{end-expr} are \exposid{range} and \exposid{range} \tcode{+} \tcode{N}, respectively, where \tcode{N} is the array bound. If \tcode{R} is an array of unknown bound or an array of incomplete type, the program is ill-formed; -\item if the \grammarterm{for-range-initializer} is -an expression of class type \tcode{C}, and +\item if the type of \exposid{range} is a reference to a +class type \tcode{C}, and searches in the scope of \tcode{C}\iref{class.member.lookup} for the names \tcode{begin} and \tcode{end} each find at least one declaration, @@ -765,7 +809,7 @@ \begin{note} On exit from a scope (however accomplished), objects with automatic storage duration\iref{basic.stc.auto} that have been constructed in that scope are destroyed -in the reverse order of their construction. +in the reverse order of their construction\iref{stmt.dcl}. For temporaries, see~\ref{class.temporary}. However, the program can be terminated (by calling \indextext{\idxcode{exit}}% @@ -846,7 +890,7 @@ \indextext{function return|see{\tcode{return}}}% \pnum -A function returns to its caller by the \tcode{return} statement. +A function returns control to its caller by the \tcode{return} statement. \pnum The \grammarterm{expr-or-braced-init-list} @@ -904,6 +948,39 @@ by the operand of the \tcode{return} statement, which, in turn, is sequenced before the destruction of local variables\iref{stmt.jump} of the block enclosing the \tcode{return} statement. +\begin{note} +These operations +are sequenced before the destruction of local variables +in each remaining enclosing block of the function\iref{stmt.dcl}, +which, in turn, +is sequenced before the evaluation of +postcondition assertions of the function\iref{dcl.contract.func}, +which, in turn, +is sequenced before the destruction of function parameters\iref{expr.call}. +\end{note} + +\pnum +In a function whose return type is a reference, +other than an invented function for \tcode{std::is_convertible}\iref{meta.rel}, +a \tcode{return} statement that binds the returned reference to +a temporary expression\iref{class.temporary} is ill-formed. +\begin{example} +\begin{codeblock} +auto&& f1() { + return 42; // ill-formed +} +const double& f2() { + static int x = 42; + return x; // ill-formed +} +auto&& id(auto&& r) { + return static_cast(r); +} +auto&& f3() { + return id(42); // OK, but probably a bug +} +\end{codeblock} +\end{example} \rSec2[stmt.return.coroutine]{The \keyword{co_return} statement}% \indextext{\idxcode{co_return}}% @@ -915,8 +992,8 @@ \end{bnf} \pnum -A coroutine returns to its caller or resumer\iref{dcl.fct.def.coroutine} -by the \keyword{co_return} statement or when suspended\iref{expr.await}. +A \keyword{co_return} statement transfers control to +the caller or resumer of a coroutine\iref{dcl.fct.def.coroutine}. A coroutine shall not enclose a \tcode{return} statement\iref{stmt.return}. \begin{note} @@ -950,7 +1027,8 @@ \end{itemize} \pnum -If \placeholder{p}\tcode{.return_void()} is a valid expression, +If a search for the name \tcode{return_void} in the scope of the promise type +finds any declarations, flowing off the end of a coroutine's \grammarterm{function-body} is equivalent to a \keyword{co_return} with no operand; otherwise flowing off the end of a coroutine's \grammarterm{function-body} @@ -965,6 +1043,48 @@ \indextext{label}% label\iref{stmt.label} located in the current function. +\rSec1[stmt.contract.assert]{Assertion statement} + +\begin{bnf} +\nontermdef{assertion-statement}\br + \terminal{contract_assert} \opt{attribute-specifier-seq} \terminal{(} conditional-expression \terminal{)} \terminal{;} +\end{bnf} + +\pnum +\indexdefn{contract assertion!statement|see{assertion, statement}} +\indextext{assertion!statement} +An \grammarterm{assertion-statement} +introduces a contract assertion\iref{basic.contract}. +The optional \grammarterm{attribute-specifier-seq} +appertains to the introduced contract assertion. + +\pnum +The predicate\iref{basic.contract.general} +of an \grammarterm{assertion-statement} +is its \grammarterm{conditional-expression} +contextually converted to \tcode{bool}. + +\pnum +The evaluation of consecutive \grammarterm{assertion-statement}s +is an evaluation in sequence\iref{basic.contract.eval} of +the contract assertions introduced +by those \grammarterm{assertion-statement}s. +\begin{note} +A sequence of \grammarterm{assertion-statement}s +can thus be repeatedly evaluated as a group. +\begin{example} +\begin{codeblock} +int f(int i) +{ + contract_assert(i == 0); // \#1 + contract_assert(i >= 0); // \#2 + return 0; +} +int g = f(0); // can evaluate \#1, \#2, \#1, \#2 +\end{codeblock} +\end{example} +\end{note} + \rSec1[stmt.dcl]{Declaration statement}% \indextext{statement!declaration} @@ -990,16 +1110,16 @@ \indextext{block (statement)!initialization in}% \indextext{initialization!automatic}% \indextext{active|see{variable, active}}% -A variable with automatic storage duration\iref{basic.stc.auto} +A block variable with automatic storage duration\iref{basic.stc.auto} is \defnx{active}{variable!active} everywhere in the scope to which it belongs after its \grammarterm{init-declarator}. \indextext{initialization!jump past}% \indextext{\idxcode{goto}!initialization and}% Upon each transfer of control (including sequential execution of statements) within a function from point $P$ to point $Q$, -all variables with automatic storage duration +all block variables with automatic storage duration that are active at $P$ and not at $Q$ are destroyed in the reverse order of their construction. -Then, all variables with automatic storage duration +Then, all block variables with automatic storage duration that are active at $Q$ but not at $P$ are initialized in declaration order; unless all such variables have vacuous initialization\iref{basic.life}, the transfer of control shall not be a jump. @@ -1093,7 +1213,7 @@ of many examples. \begin{example} Assuming \tcode{T} is a -\grammarterm{simple-type-specifier}\iref{dcl.type}, +\grammarterm{simple-type-specifier}\iref{dcl.type.simple}, \begin{codeblock} T(a)->m = 7; // expression-statement diff --git a/source/std.tex b/source/std.tex index f179e402e8..0170e31451 100644 --- a/source/std.tex +++ b/source/std.tex @@ -13,6 +13,7 @@ {listings} % code listings \usepackage{longtable} % auto-breaking tables \usepackage{ltcaption} % fix captions for long tables +\usepackage{caption} % caption style \usepackage{relsize} % provide relative font size changes \usepackage{textcomp} % provide \text{l,r}angle \usepackage{underscore} % remove special status of '_' in ordinary text @@ -23,6 +24,7 @@ \usepackage{color} % define colors for strikeouts and underlines \usepackage{amsmath} % additional math symbols \usepackage{mathrsfs} % mathscr font +\usepackage{bm} \usepackage[final]{microtype} \usepackage[splitindex,original]{imakeidx} \usepackage{multicol} @@ -40,9 +42,11 @@ linktocpage=true, colorlinks=true, linkcolor=blue, + citecolor=blue, + urlcolor=blue, % ISO/IEC Directives, Part 2, section 6.5 plainpages=false} \usepackage{memhfixc} % fix interactions between hyperref and memoir -\usepackage[active,header=false,handles=false,copydocumentclass=false,generate=std-gram.ext,extract-cmdline={gramSec},extract-env={bnf,simplebnf}]{extract} % Grammar extraction +\usepackage{environ} \usepackage{expl3} \usepackage{xparse} \usepackage{xstring} @@ -53,6 +57,10 @@ \renewcommand\RSsmallest{5.5pt} % smallest font size for relsize +% Begin grammar extraction... +\newwrite\gramout +\immediate\openout\gramout=std-gram.ext + \input{layout} \input{styles} \input{macros} @@ -84,6 +92,10 @@ %% turn off all ligatures inside \texttt \DisableLigatures{encoding = T1, family = tt*} +%%-------------------------------------------------- +%% select regular text font for \url +\urlstyle{same} + \begin{document} \chapterstyle{cppstd} \pagestyle{cpppage} @@ -121,21 +133,22 @@ \include{memory} \include{meta} \include{utilities} -\include{strings} \include{containers} \include{iterators} \include{ranges} \include{algorithms} +\include{strings} +\include{text} \include{numerics} \include{time} -\include{locales} \include{iostreams} -\include{regex} \include{threads} +\include{exec} %%-------------------------------------------------- %% appendices \appendix +\chapterstyle{cppannex} % \include and \addtocontents don't mix; see % https://tex.stackexchange.com/questions/13914/toc-numbering-problem @@ -145,6 +158,9 @@ \numberwithin{table}{chapter} +% ... end grammar extraction. +\immediate\closeout\gramout + \include{grammar} \include{limits} \include{compatibility} diff --git a/source/strings.tex b/source/strings.tex index c0213a348a..a9615c7d91 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -5,7 +5,8 @@ \pnum This Clause describes components for manipulating sequences of -any non-array trivial standard-layout\iref{term.standard.layout.type} type. +any non-array trivially copyable standard-layout\iref{term.standard.layout.type} type \tcode{T} +where \tcode{is_trivially_default_constructible_v} is \tcode{true}. Such types are called \defnx{char-like types}{char-like type}, and objects of char-like types are called \defnx{char-like objects}{char-like object} or @@ -21,9 +22,7 @@ \ref{char.traits} & Character traits & \tcode{} \\ \ref{string.view} & String view classes & \tcode{} \\ \rowsep \ref{string.classes} & String classes & \tcode{} \\ \rowsep -\ref{c.strings} & Null-terminated sequence utilities & - \tcode{}, \tcode{}, \tcode{}, - \tcode{}, \tcode{}, \tcode{} \\ +\ref{c.strings} & Null-terminated sequence utilities & \tcode{} \\ \end{libsumtab} \rSec1[char.traits]{Character traits} @@ -108,7 +107,7 @@ denotes an lvalue of type \tcode{C}. No expression which is part of the character traits requirements -specified in this subclause \ref{char.traits.require} +specified in \ref{char.traits.require} shall exit via an exception. \begin{libreqtab4d} @@ -124,15 +123,15 @@ & & \chdr{pre-/post-condition} & \\ \capsep \endhead \tcode{X::char_type} & \tcode{C} & - & compile-time \\ \rowsep + & \\ \rowsep \tcode{X::int_type} & & -(described in~\ref{char.traits.typedefs}) & compile-time \\ \rowsep +(described in~\ref{char.traits.typedefs}) & \\ \rowsep \tcode{X::off_type} & & -(described in~\ref{iostreams.limits.pos} and \ref{iostream.forward}) & compile-time \\ \rowsep +(described in~\ref{iostreams.limits.pos} and \ref{iostream.forward}) & \\ \rowsep \tcode{X::pos_type} & & -(described in~\ref{iostreams.limits.pos} and \ref{iostream.forward}) & compile-time \\ \rowsep +(described in~\ref{iostreams.limits.pos} and \ref{iostream.forward}) & \\ \rowsep \tcode{X::state_type} & & -(described in~\ref{char.traits.typedefs}) & compile-time \\ \rowsep +(described in~\ref{char.traits.typedefs}) & \\ \rowsep \tcode{X::eq(c,d)} & \tcode{bool} & \returns whether \tcode{c} is to be treated as equal to \tcode{d}. & constant \\ \rowsep @@ -141,31 +140,31 @@ whether \tcode{c} is to be treated as less than \tcode{d}. & constant \\ \rowsep \tcode{X::compare(p,q,n)} & \tcode{int} & \returns -\tcode{0} if for each \tcode{i} in \tcode{[0,n)}, \tcode{X::eq(p[i],q[i])} -is \tcode{true}; else, a negative value if, for some \tcode{j} in \tcode{[0,n)}, -\tcode{X::lt(p[j],q[j])} is \tcode{true} and for each \tcode{i} in \tcode{[0,j)} +\tcode{0} if for each \tcode{i} in \range{0}{n}, \tcode{X::eq(p[i],q[i])} +is \tcode{true}; else, a negative value if, for some \tcode{j} in \range{0}{n}, +\tcode{X::lt(p[j],q[j])} is \tcode{true} and for each \tcode{i} in \range{0}{j} \tcode{X::eq(p[i],q[i])} is \tcode{true}; else a positive value. & linear \\ \rowsep \tcode{X::length(p)} & \tcode{size_t} & \returns the smallest \tcode{i} such that \tcode{X::eq(p[i],charT())} is \tcode{true}. & linear \\ \rowsep \tcode{X::find(p,n,c)} & \tcode{const X::char_type*} & \returns -the smallest \tcode{q} in \tcode{[p,p+n)} such that +the smallest \tcode{q} in \range{p}{p+n} such that \tcode{X::eq(*q,c)} is \tcode{true}, \tcode{nullptr} otherwise. & linear \\ \rowsep \tcode{X::move(s,p,n)} & \tcode{X::char_type*} & -for each \tcode{i} in \tcode{[0,n)}, performs \tcode{X::assign(s[i],p[i])}. -Copies correctly even where the ranges \tcode{[p,p+n)} and \tcode{[s,s+n)} overlap.\br \returns \tcode{s}. & linear \\ \rowsep +for each \tcode{i} in \range{0}{n}, performs \tcode{X::assign(s[i],p[i])}. +Copies correctly even where the ranges \range{p}{p+n} and \range{s}{s+n} overlap.\br \returns \tcode{s}. & linear \\ \rowsep \tcode{X::copy(s,p,n)} & \tcode{X::char_type*} & \expects The ranges \range{p}{p+n} and \range{s}{s+n} do not overlap.\par \returns \tcode{s}.\br for each \tcode{i} in -\tcode{[0,n)}, performs \tcode{X::assign(s[i],p[i])}. & linear \\ \rowsep +\range{0}{n}, performs \tcode{X::assign(s[i],p[i])}. & linear \\ \rowsep \tcode{X::assign(r,d)} & (not used) & assigns \tcode{r=d}. & constant \\ \rowsep \tcode{X::assign\-(s,n,c)} & \tcode{X::char_type*} & -for each \tcode{i} in \tcode{[0,n)}, performs +for each \tcode{i} in \range{0}{n}, performs \tcode{X::assign(s[i],c)}.\br \returns \tcode{s}. & linear \\ \rowsep @@ -201,7 +200,7 @@ \begin{codeblock} template struct char_traits; \end{codeblock} -is provided in the header \libheader{string} +is provided in the header \libheaderref{string} as a basis for explicit specializations. \rSec2[char.traits.typedefs]{Traits typedefs} @@ -307,7 +306,7 @@ \end{codeblock} \pnum -The type \tcode{mbstate_t} is defined in \libheader{cwchar} +The type \tcode{mbstate_t} is defined in \libheaderref{cwchar} and can represent any of the conversion states that can occur in an \impldef{supported multibyte character encoding rules} set of supported multibyte character encoding rules. @@ -533,12 +532,13 @@ \indexheader{string_view}% \begin{codeblock} +// mostly freestanding #include // see \ref{compare.syn} namespace std { // \ref{string.view.template}, class template \tcode{basic_string_view} template> - class basic_string_view; + class basic_string_view; // partially freestanding template constexpr bool ranges::@\libspec{enable_view}{basic_string_view}@> = true; @@ -548,18 +548,17 @@ // \ref{string.view.comparison}, non-member comparison functions template constexpr bool operator==(basic_string_view x, - basic_string_view y) noexcept; + type_identity_t> y) noexcept; template constexpr @\seebelow@ operator<=>(basic_string_view x, - @\itcorr@ basic_string_view y) noexcept; - - // see \ref{string.view.comparison}, sufficient additional overloads of comparison functions + @\itcorr@ type_identity_t> y) noexcept; // \ref{string.view.io}, inserters and extractors template basic_ostream& operator<<(basic_ostream& os, - basic_string_view str); + basic_string_view str); // hosted // \tcode{basic_string_view} \grammarterm{typedef-name}s using string_view = basic_string_view; @@ -577,14 +576,14 @@ template<> struct hash; inline namespace literals { - inline namespace string_view_literals { - // \ref{string.view.literals}, suffix for \tcode{basic_string_view} literals - constexpr string_view operator""sv(const char* str, size_t len) noexcept; - constexpr u8string_view operator""sv(const char8_t* str, size_t len) noexcept; - constexpr u16string_view operator""sv(const char16_t* str, size_t len) noexcept; - constexpr u32string_view operator""sv(const char32_t* str, size_t len) noexcept; - constexpr wstring_view operator""sv(const wchar_t* str, size_t len) noexcept; - } + inline namespace string_view_literals { + // \ref{string.view.literals}, suffix for \tcode{basic_string_view} literals + constexpr string_view operator""sv(const char* str, size_t len) noexcept; + constexpr u8string_view operator""sv(const char8_t* str, size_t len) noexcept; + constexpr u16string_view operator""sv(const char16_t* str, size_t len) noexcept; + constexpr u32string_view operator""sv(const char32_t* str, size_t len) noexcept; + constexpr wstring_view operator""sv(const wchar_t* str, size_t len) noexcept; + } } } \end{codeblock} @@ -659,11 +658,11 @@ constexpr size_type size() const noexcept; constexpr size_type length() const noexcept; constexpr size_type max_size() const noexcept; - [[nodiscard]] constexpr bool empty() const noexcept; + constexpr bool empty() const noexcept; // \ref{string.view.access}, element access constexpr const_reference operator[](size_type pos) const; - constexpr const_reference at(size_type pos) const; + constexpr const_reference at(size_type pos) const; // freestanding-deleted constexpr const_reference front() const; constexpr const_reference back() const; constexpr const_pointer data() const noexcept; @@ -674,17 +673,22 @@ constexpr void swap(basic_string_view& s) noexcept; // \ref{string.view.ops}, string operations - constexpr 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; // freestanding-deleted - constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const; + constexpr basic_string_view substr(size_type pos = 0, + size_type n = npos) const; // freestanding-deleted constexpr int compare(basic_string_view s) const noexcept; - constexpr int compare(size_type pos1, size_type n1, basic_string_view s) const; + constexpr int compare(size_type pos1, size_type n1, + basic_string_view s) const; // freestanding-deleted constexpr int compare(size_type pos1, size_type n1, basic_string_view s, - size_type pos2, size_type n2) const; + size_type pos2, size_type n2) const; // freestanding-deleted 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 int compare(size_type pos1, size_type n1, + const charT* s) const; // freestanding-deleted + constexpr int compare(size_type pos1, size_type n1, const charT* s, + size_type n2) const; // freestanding-deleted constexpr bool starts_with(basic_string_view x) const noexcept; constexpr bool starts_with(charT x) const noexcept; @@ -751,10 +755,10 @@ any operation that invalidates a pointer in the range \begin{codeblock} -@\range{str.data()}{\brk{}str.data() + str.size()}@ +@\range{str.data()}{str.data() + str.size()}@ \end{codeblock} invalidates pointers, iterators, and references -returned from \tcode{str}'s member functions. +to elements of \tcode{str}. \pnum The complexity of \tcode{basic_string_view} member functions is \bigoh{1} @@ -1016,7 +1020,7 @@ \indexlibrarymember{empty}{basic_string_view}% \begin{itemdecl} -[[nodiscard]] constexpr bool empty() const noexcept; +constexpr bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1034,8 +1038,11 @@ \begin{itemdescr} \pnum -\expects -\tcode{pos < size()}. +\hardexpects +\tcode{pos < size()} is \tcode{true}. +\begin{note} +This precondition is stronger than the one on \tcode{basic_string::operator[]}. +\end{note} \pnum \returns @@ -1044,12 +1051,6 @@ \pnum \throws Nothing. - -\pnum -\begin{note} -Unlike \tcode{basic_string::operator[]}, -\tcode{basic_string_view::operator[](size())} has undefined behavior instead of returning \tcode{charT()}. -\end{note} \end{itemdescr} \indexlibrarymember{at}{basic_string_view}% @@ -1074,8 +1075,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +\hardexpects +\tcode{empty()} is \tcode{false}. \pnum \returns @@ -1093,8 +1094,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +\hardexpects +\tcode{empty()} is \tcode{false}. \pnum \returns @@ -1132,8 +1133,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{n <= size()}. +\hardexpects +\tcode{n <= size()} is \tcode{true}. \pnum \effects @@ -1147,8 +1148,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{n <= size()}. +\hardexpects +\tcode{n <= size()} is \tcode{true}. \pnum \effects @@ -1311,9 +1312,12 @@ \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{rlen} be the smaller of \tcode{size()} and \tcode{x.size()}. + \pnum \effects -Equivalent to: \tcode{return substr(0, x.size()) == x;} +Equivalent to: \tcode{return basic_string_view(data(), rlen) == x;} \end{itemdescr} \indexlibrarymember{starts_with}{basic_string_view}% @@ -1344,11 +1348,14 @@ \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{rlen} be the smaller of \tcode{size()} and \tcode{x.size()}. + \pnum \effects Equivalent to: \begin{codeblock} -return size() >= x.size() && compare(size() - x.size(), npos, x) == 0; +return basic_string_view(data() + (size() - rlen), rlen) == x; \end{codeblock} \end{itemdescr} @@ -1439,7 +1446,7 @@ \item \tcode{xpos + str.size() <= size()} \item -\tcode{traits::eq(at(xpos + I), str.at(I))} for all elements \tcode{I} of the string referenced by \tcode{str}. +\tcode{traits::eq(data_[xpos + I], str[I])} for all elements \tcode{I} of the string referenced by \tcode{str}. \end{itemize} \pnum @@ -1466,7 +1473,7 @@ \item \tcode{xpos + str.size() <= size()} \item -\tcode{traits::eq(at(xpos + I), str.at(I))} for all elements \tcode{I} of the string referenced by \tcode{str}. +\tcode{traits::eq(data_[xpos + I], str[I])} for all elements \tcode{I} of the string referenced by \tcode{str}. \end{itemize} \pnum @@ -1493,7 +1500,7 @@ \item \tcode{xpos < size()} \item -\tcode{traits::eq(at(xpos), str.at(I))} for some element \tcode{I} of the string referenced by \tcode{str}. +\tcode{traits::eq(data_[xpos], str[I])} for some element \tcode{I} of the string referenced by \tcode{str}. \end{itemize} \pnum @@ -1520,7 +1527,7 @@ \item \tcode{xpos < size()} \item -\tcode{traits::eq(at(xpos), str.at(I))} for some element \tcode{I} of the string referenced by \tcode{str}. +\tcode{traits::eq(data_[xpos], str[I])} for some element \tcode{I} of the string referenced by \tcode{str}. \end{itemize} \pnum @@ -1547,7 +1554,7 @@ \item \tcode{xpos < size()} \item -\tcode{traits::eq(at(xpos), str.at(I))} for no element \tcode{I} of the string referenced by \tcode{str}. +\tcode{traits::eq(data_[xpos], str[I])} for no element \tcode{I} of the string referenced by \tcode{str}. \end{itemize} \pnum @@ -1573,7 +1580,7 @@ \item \tcode{xpos < size()} \item -\tcode{traits::eq(at(xpos), str.at(I))} for no element \tcode{I} of the string referenced by \tcode{str}. +\tcode{traits::eq(data_[xpos], str[I])} for no element \tcode{I} of the string referenced by \tcode{str}. \end{itemize} \pnum @@ -1588,47 +1595,11 @@ \rSec2[string.view.comparison]{Non-member comparison functions} -\pnum -Let \tcode{S} be \tcode{basic_string_view}, and \tcode{sv} be an instance of \tcode{S}. -Implementations shall provide sufficient additional overloads marked \keyword{constexpr} and \keyword{noexcept} -so that an object \tcode{t} with an implicit conversion to \tcode{S} can be compared according to \tref{string.view.comparison.overloads}. -\begin{libtab2}{Additional \tcode{basic_string_view} comparison overloads}{string.view.comparison.overloads}{cc}{Expression}{Equivalent to} -\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)} \\ -\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)} \\ -\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)} \\ -\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: -\begin{codeblock} -template - constexpr bool operator==(basic_string_view lhs, - basic_string_view rhs) noexcept { - return lhs.compare(rhs) == 0; - } -template - constexpr bool operator==(basic_string_view lhs, - type_identity_t> rhs) noexcept { - return lhs.compare(rhs) == 0; - } -\end{codeblock} -\end{example} - \indexlibrarymember{operator==}{basic_string_view}% \begin{itemdecl} template constexpr bool operator==(basic_string_view lhs, - basic_string_view rhs) noexcept; + type_identity_t> rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -1641,7 +1612,7 @@ \begin{itemdecl} template constexpr @\seebelow@ operator<=>(basic_string_view lhs, - @\itcorr@ basic_string_view rhs) noexcept; + @\itcorr@ type_identity_t> rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -1657,6 +1628,15 @@ \pnum \returns \tcode{static_cast(lhs.compare(rhs) <=> 0)}. + +\pnum +\begin{note} +The usage of \tcode{type_identity_t} as parameter +ensures that an object of type \tcode{basic_string_view} +can always be compared with an object of a type \tcode{T} with +an implicit conversion to \tcode{basic_string_view}, and +vice versa, as per \ref{over.match.oper}. +\end{note} \end{itemdescr} \rSec2[string.view.io]{Inserters and extractors} @@ -1683,7 +1663,7 @@ \pnum \returns -\tcode{os} +\tcode{os}. \end{itemdescr} \rSec2[string.view.hash]{Hash support} @@ -1852,6 +1832,22 @@ constexpr basic_string operator+(basic_string&& lhs, charT rhs); + template + constexpr basic_string + operator+(const basic_string& lhs, + type_identity_t> rhs); + template + constexpr basic_string + operator+(basic_string&& lhs, + type_identity_t> rhs); + template + constexpr basic_string + operator+(type_identity_t> lhs, + const basic_string& rhs); + template + constexpr basic_string + operator+(type_identity_t> lhs, + basic_string&& rhs); template constexpr bool @@ -1904,7 +1900,7 @@ basic_string& str); // \ref{string.erasure}, erasure - template + template constexpr typename basic_string::size_type erase(basic_string& c, const U& value); template @@ -1975,14 +1971,14 @@ template struct hash, A>>; inline namespace literals { - inline namespace string_literals { - // \ref{basic.string.literals}, suffix for \tcode{basic_string} literals - 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); - } + inline namespace string_literals { + // \ref{basic.string.literals}, suffix for \tcode{basic_string} literals + 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); + } } } \end{codeblock} @@ -2123,7 +2119,7 @@ constexpr void reserve(size_type res_arg); constexpr void shrink_to_fit(); constexpr void clear() noexcept; - [[nodiscard]] constexpr bool empty() const noexcept; + constexpr bool empty() const noexcept; // \ref{string.access}, element access constexpr const_reference operator[](size_type pos) const; @@ -3074,7 +3070,7 @@ \indexlibrarymember{empty}{basic_string}% \begin{itemdecl} -[[nodiscard]] constexpr bool empty() const noexcept; +constexpr bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -3094,8 +3090,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{pos <= size()}. +\hardexpects +\tcode{pos <= size()} is \tcode{true}. \pnum \returns @@ -3139,8 +3135,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +\hardexpects +\tcode{empty()} is \tcode{false}. \pnum \effects @@ -3155,8 +3151,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +\hardexpects +\tcode{empty()} is \tcode{false}. \pnum \effects @@ -3738,7 +3734,7 @@ \pnum \returns -\tcode{*this} +\tcode{*this}. \pnum \throws @@ -3918,7 +3914,7 @@ \pnum \effects Removes the characters in the range -\tcode{[first, last)}. +\range{first}{last}. \pnum \returns @@ -3940,8 +3936,8 @@ \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +\hardexpects +\tcode{empty()} is \tcode{false}. \pnum \effects @@ -4867,6 +4863,85 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string + operator+(const basic_string& lhs, + type_identity_t> rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Equivalent to: +\begin{codeblock} +basic_string r = lhs; +r.append(rhs); +return r; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string + operator+(basic_string&& lhs, + type_identity_t> rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Equivalent to: +\begin{codeblock} +lhs.append(rhs); +return std::move(lhs); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string + operator+(type_identity_t> lhs, + const basic_string& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Equivalent to: +\begin{codeblock} +basic_string r = rhs; +r.insert(0, lhs); +return r; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string + operator+(type_identity_t> lhs, + basic_string&& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Equivalent to: +\begin{codeblock} +rhs.insert(0, lhs); +return std::move(rhs); +\end{codeblock} +\end{itemdescr} + +\pnum +\begin{note} +Using a specialization of \tcode{type_identity_t} as a parameter type ensures +that an object of type \tcode{basic_string} +can be concatenated with an object of a type \tcode{T} +having an implicit conversion to +\tcode{basic_string_view}\iref{over.match.oper}. +\end{note} + \rSec3[string.cmp]{Non-member comparison operator functions} \begin{itemdecl} template @@ -5067,7 +5142,7 @@ \indexlibrarymember{erase}{basic_string}% \begin{itemdecl} -template +template constexpr typename basic_string::size_type erase(basic_string& c, const U& value); \end{itemdecl} @@ -5364,106 +5439,6 @@ \rSec1[c.strings]{Null-terminated sequence utilities} -\rSec2[cctype.syn]{Header \tcode{} synopsis} - -\indexlibraryglobal{isalnum}% -\indexlibraryglobal{isalpha}% -\indexlibraryglobal{isblank}% -\indexlibraryglobal{iscntrl}% -\indexlibraryglobal{isdigit}% -\indexlibraryglobal{isgraph}% -\indexlibraryglobal{islower}% -\indexlibraryglobal{isprint}% -\indexlibraryglobal{ispunct}% -\indexlibraryglobal{isspace}% -\indexlibraryglobal{isupper}% -\indexlibraryglobal{isxdigit}% -\indexlibraryglobal{tolower}% -\indexlibraryglobal{toupper}% -\begin{codeblock} -namespace std { - int isalnum(int c); - int isalpha(int c); - int isblank(int c); - int iscntrl(int c); - int isdigit(int c); - int isgraph(int c); - int islower(int c); - int isprint(int c); - int ispunct(int c); - int isspace(int c); - int isupper(int c); - int isxdigit(int c); - int tolower(int c); - int toupper(int c); -} -\end{codeblock} - -\pnum -The contents and meaning of the header \libheaderdef{cctype} -are the same as the C standard library header \libheader{ctype.h}. - -\xrefc{7.4} - -\rSec2[cwctype.syn]{Header \tcode{} synopsis} - -\indexlibraryglobal{wint_t}% -\indexlibraryglobal{wctrans_t}% -\indexlibraryglobal{wctype_t}% -\indexlibraryglobal{iswalnum}% -\indexlibraryglobal{iswalpha}% -\indexlibraryglobal{iswblank}% -\indexlibraryglobal{iswcntrl}% -\indexlibraryglobal{iswdigit}% -\indexlibraryglobal{iswgraph}% -\indexlibraryglobal{iswlower}% -\indexlibraryglobal{iswprint}% -\indexlibraryglobal{iswpunct}% -\indexlibraryglobal{iswspace}% -\indexlibraryglobal{iswupper}% -\indexlibraryglobal{iswxdigit}% -\indexlibraryglobal{iswctype}% -\indexlibraryglobal{wctype}% -\indexlibraryglobal{towlower}% -\indexlibraryglobal{towupper}% -\indexlibraryglobal{towctrans}% -\indexlibraryglobal{wctrans}% -\indexlibraryglobal{WEOF}% -\begin{codeblock} -namespace std { - using wint_t = @\seebelow@; - using wctrans_t = @\seebelow@; - using wctype_t = @\seebelow@; - - int iswalnum(wint_t wc); - int iswalpha(wint_t wc); - int iswblank(wint_t wc); - int iswcntrl(wint_t wc); - int iswdigit(wint_t wc); - int iswgraph(wint_t wc); - int iswlower(wint_t wc); - int iswprint(wint_t wc); - int iswpunct(wint_t wc); - int iswspace(wint_t wc); - int iswupper(wint_t wc); - int iswxdigit(wint_t wc); - int iswctype(wint_t wc, wctype_t desc); - wctype_t wctype(const char* property); - wint_t towlower(wint_t wc); - wint_t towupper(wint_t wc); - wint_t towctrans(wint_t wc, wctrans_t desc); - wctrans_t wctrans(const char* property); -} - -#define WEOF @\seebelow@ -\end{codeblock} - -\pnum -The contents and meaning of the header \libheaderdef{cwctype} -are the same as the C standard library header \libheader{wctype.h}. - -\xrefc{7.30} - \rSec2[cstring.syn]{Header \tcode{} synopsis} \indexlibraryglobal{memchr}% @@ -5516,7 +5491,7 @@ size_t strspn(const char* s1, const char* s2); // freestanding const char* strstr(const char* s1, const char* s2); // freestanding; see \ref{library.c} char* strstr(char* s1, const char* s2); // freestanding; see \ref{library.c} - char* strtok(char* s1, const char* s2); // freestanding + char* strtok(char* s1, const char* s2); void* memset(void* s, int c, size_t n); // freestanding char* strerror(int errnum); size_t strlen(const char* s); // freestanding @@ -5537,9 +5512,11 @@ \indextext{signal-safe!\idxcode{memcpy}}% \indextext{signal-safe!\idxcode{memmove}}% The functions \tcode{memcpy} and \tcode{memmove} are signal-safe\iref{support.signal}. -Both functions implicitly create objects\iref{intro.object} +Each of these functions implicitly creates objects\iref{intro.object} in the destination region of storage immediately prior to copying the sequence of characters to the destination. +Each of these functions returns a pointer to a suitable created object, if any, +otherwise the value of the first parameter. \pnum \begin{note} @@ -5550,373 +5527,3 @@ \end{note} \xrefc{7.24} - -\rSec2[cwchar.syn]{Header \tcode{} synopsis} - -\indexheader{cwchar}% -\indexlibraryglobal{NULL}% -\indexlibraryglobal{WCHAR_MAX}% -\indexlibraryglobal{WCHAR_MIN}% -\indexlibraryglobal{WEOF}% -\indexlibraryglobal{btowc}% -\indexlibraryglobal{fgetwc}% -\indexlibraryglobal{fgetws}% -\indexlibraryglobal{fputwc}% -\indexlibraryglobal{fputws}% -\indexlibraryglobal{fwide}% -\indexlibraryglobal{fwprintf}% -\indexlibraryglobal{fwscanf}% -\indexlibraryglobal{getwchar}% -\indexlibraryglobal{getwc}% -\indexlibraryglobal{mbrlen}% -\indexlibraryglobal{mbrtowc}% -\indexlibraryglobal{mbsinit}% -\indexlibraryglobal{mbsrtowcs}% -\indexlibraryglobal{mbstate_t}% -\indexlibraryglobal{putwchar}% -\indexlibraryglobal{putwc}% -\indexlibraryglobal{size_t}% -\indexlibraryglobal{swprintf}% -\indexlibraryglobal{swscanf}% -\indexlibraryglobal{tm}% -\indexlibraryglobal{ungetwc}% -\indexlibraryglobal{vfwprintf}% -\indexlibraryglobal{vfwscanf}% -\indexlibraryglobal{vswprintf}% -\indexlibraryglobal{vswscanf}% -\indexlibraryglobal{vwprintf}% -\indexlibraryglobal{vwscanf}% -\indexlibraryglobal{wcrtomb}% -\indexlibraryglobal{wcscat}% -\indexlibraryglobal{wcschr}% -\indexlibraryglobal{wcscmp}% -\indexlibraryglobal{wcscoll}% -\indexlibraryglobal{wcscpy}% -\indexlibraryglobal{wcscspn}% -\indexlibraryglobal{wcsftime}% -\indexlibraryglobal{wcslen}% -\indexlibraryglobal{wcsncat}% -\indexlibraryglobal{wcsncmp}% -\indexlibraryglobal{wcsncpy}% -\indexlibraryglobal{wcspbrk}% -\indexlibraryglobal{wcsrchr}% -\indexlibraryglobal{wcsrtombs}% -\indexlibraryglobal{wcsspn}% -\indexlibraryglobal{wcsstr}% -\indexlibraryglobal{wcstod}% -\indexlibraryglobal{wcstof}% -\indexlibraryglobal{wcstok}% -\indexlibraryglobal{wcstold}% -\indexlibraryglobal{wcstoll}% -\indexlibraryglobal{wcstol}% -\indexlibraryglobal{wcstoull}% -\indexlibraryglobal{wcstoul}% -\indexlibraryglobal{wcsxfrm}% -\indexlibraryglobal{wctob}% -\indexlibraryglobal{wint_t}% -\indexlibraryglobal{wmemchr}% -\indexlibraryglobal{wmemcmp}% -\indexlibraryglobal{wmemcpy}% -\indexlibraryglobal{wmemmove}% -\indexlibraryglobal{wmemset}% -\indexlibraryglobal{wprintf}% -\indexlibraryglobal{wscanf}% -\begin{codeblock} -namespace std { - using size_t = @\textit{see \ref{support.types.layout}}@; // freestanding - using mbstate_t = @\seebelow@; // freestanding - using wint_t = @\seebelow@; // freestanding - - struct tm; - - int fwprintf(FILE* stream, const wchar_t* format, ...); - int fwscanf(FILE* stream, const wchar_t* format, ...); - int swprintf(wchar_t* s, size_t n, const wchar_t* format, ...); - int swscanf(const wchar_t* s, const wchar_t* format, ...); - int vfwprintf(FILE* stream, const wchar_t* format, va_list arg); - int vfwscanf(FILE* stream, const wchar_t* format, va_list arg); - int vswprintf(wchar_t* s, size_t n, const wchar_t* format, va_list arg); - int vswscanf(const wchar_t* s, const wchar_t* format, va_list arg); - int vwprintf(const wchar_t* format, va_list arg); - int vwscanf(const wchar_t* format, va_list arg); - int wprintf(const wchar_t* format, ...); - int wscanf(const wchar_t* format, ...); - wint_t fgetwc(FILE* stream); - wchar_t* fgetws(wchar_t* s, int n, FILE* stream); - wint_t fputwc(wchar_t c, FILE* stream); - int fputws(const wchar_t* s, FILE* stream); - int fwide(FILE* stream, int mode); - wint_t getwc(FILE* stream); - wint_t getwchar(); - wint_t putwc(wchar_t c, FILE* stream); - wint_t putwchar(wchar_t c); - wint_t ungetwc(wint_t c, FILE* stream); - double wcstod(const wchar_t* nptr, wchar_t** endptr); - float wcstof(const wchar_t* nptr, wchar_t** endptr); - long double wcstold(const wchar_t* nptr, wchar_t** endptr); - long int wcstol(const wchar_t* nptr, wchar_t** endptr, int base); - long long int wcstoll(const wchar_t* nptr, wchar_t** endptr, int base); - unsigned long int wcstoul(const wchar_t* nptr, wchar_t** endptr, int base); - unsigned long long int wcstoull(const wchar_t* nptr, wchar_t** endptr, int base); - wchar_t* wcscpy(wchar_t* s1, const wchar_t* s2); // freestanding - wchar_t* wcsncpy(wchar_t* s1, const wchar_t* s2, size_t n); // freestanding - wchar_t* wmemcpy(wchar_t* s1, const wchar_t* s2, size_t n); // freestanding - wchar_t* wmemmove(wchar_t* s1, const wchar_t* s2, size_t n); // freestanding - wchar_t* wcscat(wchar_t* s1, const wchar_t* s2); // freestanding - wchar_t* wcsncat(wchar_t* s1, const wchar_t* s2, size_t n); // freestanding - int wcscmp(const wchar_t* s1, const wchar_t* s2); // freestanding - int wcscoll(const wchar_t* s1, const wchar_t* s2); - int wcsncmp(const wchar_t* s1, const wchar_t* s2, size_t n); // freestanding - size_t wcsxfrm(wchar_t* s1, const wchar_t* s2, size_t n); - int wmemcmp(const wchar_t* s1, const wchar_t* s2, size_t n); // freestanding - const wchar_t* wcschr(const wchar_t* s, wchar_t c); // freestanding; see \ref{library.c} - wchar_t* wcschr(wchar_t* s, wchar_t c); // freestanding; see \ref{library.c} - size_t wcscspn(const wchar_t* s1, const wchar_t* s2); // freestanding - const wchar_t* wcspbrk(const wchar_t* s1, const wchar_t* s2); // freestanding; see \ref{library.c} - wchar_t* wcspbrk(wchar_t* s1, const wchar_t* s2); // freestanding; see \ref{library.c} - const wchar_t* wcsrchr(const wchar_t* s, wchar_t c); // freestanding; see \ref{library.c} - wchar_t* wcsrchr(wchar_t* s, wchar_t c); // freestanding; see \ref{library.c} - size_t wcsspn(const wchar_t* s1, const wchar_t* s2); // freestanding - const wchar_t* wcsstr(const wchar_t* s1, const wchar_t* s2); // freestanding; see \ref{library.c} - wchar_t* wcsstr(wchar_t* s1, const wchar_t* s2); // freestanding; see \ref{library.c} - wchar_t* wcstok(wchar_t* s1, const wchar_t* s2, wchar_t** ptr); // freestanding - const wchar_t* wmemchr(const wchar_t* s, wchar_t c, size_t n); // freestanding; see \ref{library.c} - wchar_t* wmemchr(wchar_t* s, wchar_t c, size_t n); // freestanding; see \ref{library.c} - size_t wcslen(const wchar_t* s); // freestanding - wchar_t* wmemset(wchar_t* s, wchar_t c, size_t n); // freestanding - size_t wcsftime(wchar_t* s, size_t maxsize, const wchar_t* format, const tm* timeptr); - wint_t btowc(int c); - int wctob(wint_t c); - - // \ref{c.mb.wcs}, multibyte / wide string and character conversion functions - int mbsinit(const mbstate_t* ps); - size_t mbrlen(const char* s, size_t n, mbstate_t* ps); - size_t mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps); - size_t wcrtomb(char* s, wchar_t wc, mbstate_t* ps); - size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps); - size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps); -} - -#define NULL @\textit{see \ref{support.types.nullptr}}@ // freestanding -#define WCHAR_MAX @\seebelow@ // freestanding -#define WCHAR_MIN @\seebelow@ // freestanding -#define WEOF @\seebelow@ // freestanding -\end{codeblock} - -\pnum -The contents and meaning of the header \libheader{cwchar} -are the same as the C standard library header -\libheader{wchar.h}, except that it does not declare a type \keyword{wchar_t}. - -\pnum -\begin{note} -The functions -\tcode{wcschr}, \tcode{wcspbrk}, \tcode{wcsrchr}, \tcode{wcsstr}, and \tcode{wmemchr} -have different signatures in this document, -but they have the same behavior as in the C standard library\iref{library.c}. -\end{note} - -\xrefc{7.29} - -\rSec2[cuchar.syn]{Header \tcode{} synopsis} - -\indexlibraryglobal{mbstate_t}% -\indexlibraryglobal{size_t}% -\indexlibraryglobal{mbrtoc8}% -\indexlibraryglobal{c8rtomb}% -\indexlibraryglobal{mbrtoc16}% -\indexlibraryglobal{c16rtomb}% -\indexlibraryglobal{mbrtoc32}% -\indexlibraryglobal{c32rtomb}% -\begin{codeblock} -namespace std { - using mbstate_t = @\seebelow@; - using size_t = @\textit{see \ref{support.types.layout}}@; - - size_t mbrtoc8(char8_t* pc8, const char* s, size_t n, mbstate_t* ps); - size_t c8rtomb(char* s, char8_t c8, mbstate_t* ps); - size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps); - size_t c16rtomb(char* s, char16_t c16, mbstate_t* ps); - size_t mbrtoc32(char32_t* pc32, const char* s, size_t n, mbstate_t* ps); - size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps); -} -\end{codeblock} - -\pnum -The contents and meaning of the header \libheaderdef{cuchar} -are the same as the C standard library header -\libheader{uchar.h}, except that it -declares the additional \tcode{mbrtoc8} and \tcode{c8rtomb} functions -and does not declare types \keyword{char16_t} nor \keyword{char32_t}. - -\xrefc{7.28} - -\rSec2[c.mb.wcs]{Multibyte / wide string and character conversion functions} - -\pnum -\begin{note} -The headers \libheaderref{cstdlib}, -\libheaderref{cuchar}, -and \libheaderref{cwchar} -declare the functions described in this subclause. -\end{note} - -\indexlibraryglobal{mbsinit}% -\indexlibraryglobal{mblen}% -\indexlibraryglobal{mbstowcs}% -\indexlibraryglobal{wcstombs}% -\begin{itemdecl} -int mbsinit(const mbstate_t* ps); -int mblen(const char* s, size_t n); -size_t mbstowcs(wchar_t* pwcs, const char* s, size_t n); -size_t wcstombs(char* s, const wchar_t* pwcs, size_t n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -These functions have the semantics specified in the C standard library. -\end{itemdescr} - -\xrefc{7.22.7.1, 7.22.8, 7.29.6.2.1} - -\indexlibraryglobal{mbtowc}% -\indexlibraryglobal{wctomb}% -\begin{itemdecl} -int mbtowc(wchar_t* pwc, const char* s, size_t n); -int wctomb(char* s, wchar_t wchar); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -These functions have the semantics specified in the C standard library. - -\pnum -\remarks -Calls to these functions -may introduce a data race\iref{res.on.data.races} -with other calls to the same function. -\end{itemdescr} - -\xrefc{7.22.7} - -\indexlibraryglobal{mbrlen}% -\indexlibraryglobal{mbrstowcs}% -\indexlibraryglobal{wcrstombs}% -\indexlibraryglobal{mbrtowc}% -\indexlibraryglobal{wcrtomb}% -\begin{itemdecl} -size_t mbrlen(const char* s, size_t n, mbstate_t* ps); -size_t mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps); -size_t wcrtomb(char* s, wchar_t wc, mbstate_t* ps); -size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps); -size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -These functions have the semantics specified in the C standard library. - -\pnum -\remarks -Calling these functions -with an \tcode{mbstate_t*} argument that is a null pointer value -may introduce a data race\iref{res.on.data.races} -with other calls to the same function -with an \tcode{mbstate_t*} argument that is a null pointer value. -\end{itemdescr} - -\xrefc{7.29.6.3} - -\indexlibraryglobal{mbrtoc8}% -\begin{itemdecl} -size_t mbrtoc8(char8_t* pc8, const char* s, size_t n, mbstate_t* ps); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{s} is a null pointer, -equivalent to \tcode{mbrtoc8(nullptr, "", 1, ps)}. -Otherwise, the function inspects at most \tcode{n} bytes -beginning with the byte pointed to by \tcode{s} -to determine the number of bytes needed to complete -the next multibyte character (including any shift sequences). -If the function determines -that the next multibyte character is complete and valid, -\indextext{UTF-8}% -it determines the values of the corresponding UTF-8 code units and then, -if \tcode{pc8} is not a null pointer, -stores the value of the first (or only) such code unit -in the object pointed to by \tcode{pc8}. -Subsequent calls will store successive UTF-8 code units -without consuming any additional input -until all the code units have been stored. -If the corresponding Unicode character is \unicode{0000}{null}, -the resulting state described is the initial conversion state. - -\pnum -\returns -The first of the following that applies (given the current conversion state): -\begin{itemize} -\item \tcode{0}, if the next \tcode{n} or fewer bytes complete -the multibyte character -that corresponds to the \unicode{0000}{null} Unicode character -(which is the value stored). -\item between \tcode{1} and \tcode{n} (inclusive), -if the next n or fewer bytes complete a valid multibyte character -(whose first (or only) code unit is stored); -the value returned is the number of bytes that complete the multibyte character. -\item \tcode{(size_t)(-3)}, if the next code unit -resulting from a previous call has been stored -(no bytes from the input have been consumed by this call). -\item \tcode{(size_t)(-2)}, if the next \tcode{n} bytes -contribute to an incomplete (but potentially valid) multibyte character, and -all \tcode{n} bytes have been processed (no value is stored). -\item \tcode{(size_t)(-1)}, if an encoding error occurs, -in which case the next \tcode{n} or fewer bytes do not contribute to -a complete and valid multibyte character (no value is stored); -the value of the macro \tcode{EILSEQ} is stored in \tcode{errno}, and -the conversion state is unspecified. -\end{itemize} -\end{itemdescr} - -\indexlibraryglobal{c8rtomb}% -\begin{itemdecl} -size_t c8rtomb(char* s, char8_t c8, mbstate_t* ps); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{s} is a null pointer, equivalent to -\tcode{c8rtomb(buf, u8'$\backslash$0', ps)} -where \tcode{buf} is an internal buffer. -\indextext{UTF-8}% -Otherwise, if \tcode{c8} completes a sequence of valid UTF-8 code units, -determines the number of bytes needed -to represent the multibyte character (including any shift sequences), -and stores the multibyte character representation in the array -whose first element is pointed to by \tcode{s}. -At most \tcode{MB_CUR_MAX} bytes are stored. -If the multibyte character is a null character, a null byte is stored, -preceded by any shift sequence needed to restore the initial shift state; -the resulting state described is the initial conversion state. - -\pnum -\returns -The number of bytes stored in the array object (including any shift sequences). -If \tcode{c8} does not contribute to a sequence of \keyword{char8_t} -corresponding to a valid multibyte character, -the value of the macro \tcode{EILSEQ} is stored in \tcode{errno}, -\tcode{(size_t) (-1)} is returned, and the conversion state is unspecified. - -\pnum -\remarks -Calls to \tcode{c8rtomb} with a null pointer argument for \tcode{s} -may introduce a data race\iref{res.on.data.races} -with other calls to \tcode{c8rtomb} -with a null pointer argument for \tcode{s}. -\end{itemdescr} diff --git a/source/styles.tex b/source/styles.tex index 9258953c1c..224c99d1e1 100644 --- a/source/styles.tex +++ b/source/styles.tex @@ -5,11 +5,11 @@ % footnotes %%-------------------------------------------------- -%% create chapter style +%% create chapter styles \makechapterstyle{cppstd}{% - \renewcommand{\beforechapskip}{\onelineskip} - \renewcommand{\afterchapskip}{\onelineskip} + \setlength{\beforechapskip}{\onelineskip} + \setlength{\afterchapskip}{\onelineskip} \renewcommand{\chapternamenum}{} \renewcommand{\chapnamefont}{\chaptitlefont} \renewcommand{\chapnumfont}{\chaptitlefont} @@ -17,14 +17,24 @@ \renewcommand{\afterchapternum}{} } +\makechapterstyle{cppannex}{% + \setlength{\beforechapskip}{\onelineskip} + \setlength{\afterchapskip}{\onelineskip} + \renewcommand{\chapternamenum}{} + \renewcommand{\chapnamefont}{\chaptitlefont} + \renewcommand{\chapnumfont}{\chaptitlefont} + \renewcommand{\printchapternum}{\chapnumfont\centering\thechapter\protect\\} + \renewcommand{\afterchapternum}{} +} + %%-------------------------------------------------- %% create page styles \makepagestyle{cpppage} -\makeevenhead{cpppage}{\copyright\,\textsc{ISO/IEC}}{}{\textbf{\docno}} -\makeoddhead{cpppage}{\copyright\,\textsc{ISO/IEC}}{}{\textbf{\docno}} -\makeevenfoot{cpppage}{\leftmark}{}{\thepage} -\makeoddfoot{cpppage}{\leftmark}{}{\thepage} +\makeevenhead{cpppage}{}{\textbf{\docno}}{} + \makeoddhead{cpppage}{}{\textbf{\docno}}{} +\makeevenfoot{cpppage}{\leftmark\\\mbox{}}{}{\copyright\,\textsc{ISO/IEC}\\\thepage} + \makeoddfoot{cpppage}{\leftmark\\\mbox{}}{}{\copyright\,\textsc{ISO/IEC}\\\thepage} \makeatletter \makepsmarks{cpppage}{% @@ -86,7 +96,7 @@ %%-------------------------------------------------- % set heading style for annexes -\newcommand{\Annex}[3]{\chapter[#2]{(#3)\protect\\#2\hfill[#1]}\relax\annexlabel{#1}} +\newcommand{\Annex}[3]{\chapter[#2]{\textnormal{(#3)}\protect\\[3ex]#2\hfill[#1]}\relax\annexlabel{#1}} \newcommand{\infannex}[2]{\addxref{#1}\Annex{#1}{#2}{informative}} \newcommand{\normannex}[2]{\addxref{#1}\Annex{#1}{#2}{normative}} @@ -111,8 +121,10 @@ leftmargin=\bnfindentrest, listparindent=-\bnfindentinc, itemindent=\listparindent} %%-------------------------------------------------- -%% set caption style -\captionstyle{\centering} +%% set caption styles +\DeclareCaptionLabelSeparator{emdash}{ --- } +\captionsetup{justification=centering,labelsep=emdash,font+=bf} +\captionsetup[lstlisting]{justification=raggedright,singlelinecheck=false,font=normal} %%-------------------------------------------------- %% set global styles that get reset by \mainmatter @@ -163,15 +175,17 @@ \else \lst@ifdisplaystyle \lst@EveryDisplay - % make penalty configurable - \par\lst@beginpenalty + \par\lst@beginpenalty % penalty is now configurable \vspace\lst@aboveskip \fi \fi \normalbaselines \abovecaptionskip\lst@abovecaption\relax \belowcaptionskip\lst@belowcaption\relax - \lst@MakeCaption t% + \let\savedallowbreak\allowbreak + \let\allowbreak\relax + \lst@MakeCaption t% % neuter \allowbreak before non-existing top caption + \let\allowbreak\savedallowbreak \lsthk@PreInit \lsthk@Init \lst@ifdisplaystyle \global\let\lst@ltxlabel\@empty diff --git a/source/support.tex b/source/support.tex index 4376a443cf..7d53612aad 100644 --- a/source/support.tex +++ b/source/support.tex @@ -17,6 +17,7 @@ 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}. @@ -29,10 +30,11 @@ \ref{support.arith.types} & Arithmetic types & \tcode{}, \tcode{} \\ \rowsep \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.rtti} & Type identification & \tcode{}, \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.contract} & Contract-violation handling & \tcode{} \\ \rowsep +\ref{support.initlist} & Initializer lists & \tcode{} \\ \rowsep \ref{cmp} & Comparisons & \tcode{} \\ \rowsep \ref{support.coroutine} & Coroutines & \tcode{} \\ \rowsep \ref{support.runtime} & Other runtime support & @@ -333,9 +335,10 @@ \pnum The type \indexlibraryglobal{max_align_t}% -\tcode{max_align_t} is a trivial standard-layout type whose alignment requirement +\tcode{max_align_t} is a trivially copyable standard-layout type whose alignment requirement is at least as great as that of every scalar type, and whose alignment requirement is supported in every context\iref{basic.align}. +\tcode{std::is_trivially_default_constructible_v} is \tcode{true}. \xrefc{7.19} @@ -546,15 +549,18 @@ after inclusion of any member of the set of library headers indicated in the corresponding comment in this synopsis. \begin{note} -Future revisions of \Cpp{} might replace +Future revisions of this document might replace the values of these macros with greater values. \end{note} \begin{codeblock} #define @\defnlibxname{cpp_lib_adaptor_iterator_pair_constructor}@ 202106L // also in \libheader{stack}, \libheader{queue} #define @\defnlibxname{cpp_lib_addressof_constexpr}@ 201603L // freestanding, also in \libheader{memory} +#define @\defnlibxname{cpp_lib_algorithm_default_value_type}@ 202403L + // also in \libheader{algorithm}, \libheader{ranges}, \libheader{string}, \libheader{deque}, \libheader{list}, \libheader{forward_list}, \libheader{vector} #define @\defnlibxname{cpp_lib_algorithm_iterator_requirements}@ 202207L // also in \libheader{algorithm}, \libheader{numeric}, \libheader{memory} +#define @\defnlibxname{cpp_lib_aligned_accessor}@ 202411L // also in \libheader{mdspan} #define @\defnlibxname{cpp_lib_allocate_at_least}@ 202302L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_allocator_traits_is_always_equal}@ 201411L // freestanding, also in \libheader{memory}, \libheader{scoped_allocator}, \libheader{string}, \libheader{deque}, \libheader{forward_list}, \libheader{list}, @@ -572,7 +578,8 @@ #define @\defnlibxname{cpp_lib_atomic_float}@ 201711L // freestanding, also in \libheader{atomic} #define @\defnlibxname{cpp_lib_atomic_is_always_lock_free}@ 201603L // freestanding, also in \libheader{atomic} #define @\defnlibxname{cpp_lib_atomic_lock_free_type_aliases}@ 201907L // also in \libheader{atomic} -#define @\defnlibxname{cpp_lib_atomic_ref}@ 201806L // freestanding, also in \libheader{atomic} +#define @\defnlibxname{cpp_lib_atomic_min_max}@ 202403L // freestanding, also in \libheader{atomic} +#define @\defnlibxname{cpp_lib_atomic_ref}@ 202411L // freestanding, also in \libheader{atomic} #define @\defnlibxname{cpp_lib_atomic_shared_ptr}@ 201711L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_atomic_value_initialization}@ 201911L // freestanding, also in \libheader{atomic}, \libheader{memory} #define @\defnlibxname{cpp_lib_atomic_wait}@ 201907L // freestanding, also in \libheader{atomic} @@ -593,32 +600,52 @@ #define @\defnlibxname{cpp_lib_chrono}@ 202306L // also in \libheader{chrono} #define @\defnlibxname{cpp_lib_chrono_udls}@ 201304L // also in \libheader{chrono} #define @\defnlibxname{cpp_lib_clamp}@ 201603L // also in \libheader{algorithm} -#define @\defnlibxname{cpp_lib_common_reference}@ 202302L // also in \libheader{type_traits} -#define @\defnlibxname{cpp_lib_common_reference_wrapper}@ 202302L // also in \libheader{functional} +#define @\defnlibxname{cpp_lib_common_reference}@ 202302L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_common_reference_wrapper}@ 202302L // freestanding, also in \libheader{functional} #define @\defnlibxname{cpp_lib_complex_udls}@ 201309L // also in \libheader{complex} #define @\defnlibxname{cpp_lib_concepts}@ 202207L // freestanding, also in \libheader{concepts}, \libheader{compare} #define @\defnlibxname{cpp_lib_constexpr_algorithms}@ 202306L // also in \libheader{algorithm}, \libheader{utility} +#define @\defnlibxname{cpp_lib_constexpr_atomic}@ 202411L // also in \libheader{atomic} #define @\defnlibxname{cpp_lib_constexpr_bitset}@ 202207L // also in \libheader{bitset} -#define @\defnlibxname{cpp_lib_constexpr_charconv}@ 202207L // also in \libheader{charconv} +#define @\defnlibxname{cpp_lib_constexpr_charconv}@ 202207L // freestanding, also in \libheader{charconv} #define @\defnlibxname{cpp_lib_constexpr_cmath}@ 202306L // also in \libheader{cmath}, \libheader{cstdlib} #define @\defnlibxname{cpp_lib_constexpr_complex}@ 202306L // also in \libheader{complex} +#define @\defnlibxname{cpp_lib_constexpr_deque}@ 202502L // also in \libheader{deque} #define @\defnlibxname{cpp_lib_constexpr_dynamic_alloc}@ 201907L // also in \libheader{memory} +#define @\defnlibxname{cpp_lib_constexpr_exceptions}@ 202502L + // also in \libheader{exception}, \libheader{stdexcept}, \libheader{expected}, \libheader{optional}, \libheader{variant}, and \libheader{format} +#define @\defnlibxname{cpp_lib_constexpr_flat_map}@ 202502L // also in \libheader{flat_map} +#define @\defnlibxname{cpp_lib_constexpr_flat_set}@ 202502L // also in \libheader{flat_set} +#define @\defnlibxname{cpp_lib_constexpr_forward_list}@ 202502L // also in \libheader{forward_list} #define @\defnlibxname{cpp_lib_constexpr_functional}@ 201907L // freestanding, also in \libheader{functional} +#define @\defnlibxname{cpp_lib_constexpr_inplace_vector}@ 202502L // also in \libheader{inplace_vector} #define @\defnlibxname{cpp_lib_constexpr_iterator}@ 201811L // freestanding, also in \libheader{iterator} +#define @\defnlibxname{cpp_lib_constexpr_list}@ 202502L // also in \libheader{list} +#define @\defnlibxname{cpp_lib_constexpr_map}@ 202502L // also in \libheader{map} #define @\defnlibxname{cpp_lib_constexpr_memory}@ 202202L // freestanding, also in \libheader{memory} +#define @\defnlibxname{cpp_lib_constexpr_new}@ 202406L // freestanding, also in \libheader{new} #define @\defnlibxname{cpp_lib_constexpr_numeric}@ 201911L // also in \libheader{numeric} +#define @\defnlibxname{cpp_lib_constexpr_queue}@ 202502L // also in \libheader{queue} +#define @\defnlibxname{cpp_lib_constexpr_set}@ 202502L // also in \libheader{set} +#define @\defnlibxname{cpp_lib_constexpr_stack}@ 202502L // also in \libheader{stack} #define @\defnlibxname{cpp_lib_constexpr_string}@ 201907L // also in \libheader{string} #define @\defnlibxname{cpp_lib_constexpr_string_view}@ 201811L // also in \libheader{string_view} #define @\defnlibxname{cpp_lib_constexpr_tuple}@ 201811L // freestanding, also in \libheader{tuple} #define @\defnlibxname{cpp_lib_constexpr_typeinfo}@ 202106L // freestanding, also in \libheader{typeinfo} +#define @\defnlibxname{cpp_lib_constexpr_unordered_map}@ 202502L // also in \libheader{unordered_map} +#define @\defnlibxname{cpp_lib_constexpr_unordered_set}@ 202502L // also in \libheader{unordered_set} #define @\defnlibxname{cpp_lib_constexpr_utility}@ 201811L // freestanding, also in \libheader{utility} #define @\defnlibxname{cpp_lib_constexpr_vector}@ 201907L // also in \libheader{vector} +#define @\defnlibxname{cpp_lib_constrained_equality}@ 202411L // freestanding, + // also in \libheader{utility}, \libheader{tuple}, \libheader{optional}, \libheader{variant}, \libheader{expected} #define @\defnlibxname{cpp_lib_containers_ranges}@ 202202L // also in \libheader{vector}, \libheader{list}, \libheader{forward_list}, \libheader{map}, \libheader{set}, \libheader{unordered_map}, \libheader{unordered_set}, // \libheader{deque}, \libheader{queue}, \libheader{stack}, \libheader{string} +#define @\defnlibxname{cpp_lib_contracts}@ 202502L // freestanding, also in \libheader{contracts} #define @\defnlibxname{cpp_lib_copyable_function}@ 202306L // also in \libheader{functional} -#define @\defnlibxname{cpp_lib_coroutine}@ 201902L // also in \libheader{coroutine} +#define @\defnlibxname{cpp_lib_coroutine}@ 201902L // freestanding, also in \libheader{coroutine} +#define @\defnlibxname{cpp_lib_debugging}@ 202403L // freestanding, also in \libheader{debugging} #define @\defnlibxname{cpp_lib_destroying_delete}@ 201806L // freestanding, also in \libheader{new} #define @\defnlibxname{cpp_lib_enable_shared_from_this}@ 201603L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_endian}@ 201907L // freestanding, also in \libheader{bit} @@ -631,26 +658,38 @@ #define @\defnlibxname{cpp_lib_filesystem}@ 201703L // also in \libheader{filesystem} #define @\defnlibxname{cpp_lib_flat_map}@ 202207L // also in \libheader{flat_map} #define @\defnlibxname{cpp_lib_flat_set}@ 202207L // also in \libheader{flat_set} -#define @\defnlibxname{cpp_lib_format}@ 202306L // also in \libheader{format} +#define @\defnlibxname{cpp_lib_format}@ 202311L // also in \libheader{format} #define @\defnlibxname{cpp_lib_format_ranges}@ 202207L // also in \libheader{format} +#define @\defnlibxname{cpp_lib_format_path}@ 202403L // also in \libheader{filesystem} +#define @\defnlibxname{cpp_lib_format_uchar}@ 202311L // also in \libheader{format} #define @\defnlibxname{cpp_lib_formatters}@ 202302L // also in \libheader{stacktrace}, \libheader{thread} #define @\defnlibxname{cpp_lib_forward_like}@ 202207L // freestanding, also in \libheader{utility} +#define @\defnlibxname{cpp_lib_freestanding_algorithm}@ 202502L // freestanding, also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_freestanding_array}@ 202311L // freestanding, also in \libheader{array} #define @\defnlibxname{cpp_lib_freestanding_char_traits}@ 202306L // freestanding, also in \libheader{string} #define @\defnlibxname{cpp_lib_freestanding_charconv}@ 202306L // freestanding, also in \libheader{charconv} #define @\defnlibxname{cpp_lib_freestanding_cstdlib}@ 202306L // freestanding, also in \libheader{cstdlib}, \libheader{cmath} -#define @\defnlibxname{cpp_lib_freestanding_cstring}@ 202306L // freestanding, also in \libheader{cstring} +#define @\defnlibxname{cpp_lib_freestanding_cstring}@ 202311L // freestanding, also in \libheader{cstring} #define @\defnlibxname{cpp_lib_freestanding_cwchar}@ 202306L // freestanding, also in \libheader{cwchar} #define @\defnlibxname{cpp_lib_freestanding_errc}@ 202306L // freestanding, also in \libheader{cerrno}, \libheader{system_error} +#define @\defnlibxname{cpp_lib_freestanding_execution}@ 202502L // freestanding, also in \libheader{execution} +#define @\defnlibxname{cpp_lib_freestanding_expected}@ 202311L // freestanding, also in \libheader{expected} #define @\defnlibxname{cpp_lib_freestanding_feature_test_macros}@ 202306L // freestanding #define @\defnlibxname{cpp_lib_freestanding_functional}@ 202306L // freestanding, also in \libheader{functional} #define @\defnlibxname{cpp_lib_freestanding_iterator}@ 202306L // freestanding, also in \libheader{iterator} -#define @\defnlibxname{cpp_lib_freestanding_memory}@ 202306L // freestanding, also in \libheader{memory} +#define @\defnlibxname{cpp_lib_freestanding_mdspan}@ 202311L // freestanding, also in \libheader{mdspan} +#define @\defnlibxname{cpp_lib_freestanding_memory}@ 202502L // freestanding, also in \libheader{memory} +#define @\defnlibxname{cpp_lib_freestanding_numeric}@ 202502L // freestanding, also in \libheader{numeric} #define @\defnlibxname{cpp_lib_freestanding_operator_new}@ @\seebelow@ // freestanding, also in \libheader{new} +#define @\defnlibxname{cpp_lib_freestanding_optional}@ 202311L // freestanding, also in \libheader{optional} +#define @\defnlibxname{cpp_lib_freestanding_random}@ 202502L // freestanding, also in \libheader{random} #define @\defnlibxname{cpp_lib_freestanding_ranges}@ 202306L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_freestanding_ratio}@ 202306L // freestanding, also in \libheader{ratio} +#define @\defnlibxname{cpp_lib_freestanding_string_view}@ 202311L // freestanding, also in \libheader{string_view} #define @\defnlibxname{cpp_lib_freestanding_tuple}@ 202306L // freestanding, also in \libheader{tuple} #define @\defnlibxname{cpp_lib_freestanding_utility}@ 202306L // freestanding, also in \libheader{utility} +#define @\defnlibxname{cpp_lib_freestanding_variant}@ 202311L // freestanding, also in \libheader{variant} #define @\defnlibxname{cpp_lib_fstream_native_handle}@ 202306L // also in \libheader{fstream} #define @\defnlibxname{cpp_lib_function_ref}@ 202306L // also in \libheader{functional} #define @\defnlibxname{cpp_lib_gcd_lcm}@ 201606L // also in \libheader{numeric} @@ -661,9 +700,12 @@ #define @\defnlibxname{cpp_lib_hardware_interference_size}@ 201703L // freestanding, also in \libheader{new} #define @\defnlibxname{cpp_lib_has_unique_object_representations}@ 201606L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_hazard_pointer}@ 202306L // also in \libheader{hazard_pointer} +#define @\defnlibxname{cpp_lib_hive}@ 202502L // also in \libheader{hive} #define @\defnlibxname{cpp_lib_hypot}@ 201603L // also in \libheader{cmath} #define @\defnlibxname{cpp_lib_incomplete_container_elements}@ 201505L // also in \libheader{forward_list}, \libheader{list}, \libheader{vector} +#define @\defnlibxname{cpp_lib_indirect}@ 202502L // also in \libheader{memory} +#define @\defnlibxname{cpp_lib_inplace_vector}@ 202406L // also in \libheader{inplace_vector} #define @\defnlibxname{cpp_lib_int_pow2}@ 202002L // freestanding, also in \libheader{bit} #define @\defnlibxname{cpp_lib_integer_comparison_functions}@ 202002L // also in \libheader{utility} #define @\defnlibxname{cpp_lib_integer_sequence}@ 201304L // freestanding, also in \libheader{utility} @@ -675,18 +717,21 @@ #define @\defnlibxname{cpp_lib_is_aggregate}@ 201703L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_constant_evaluated}@ 201811L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_final}@ 201402L // freestanding, also in \libheader{type_traits} -#define @\defnlibxname{cpp_lib_is_implicit_lifetime}@ 202302L // also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_is_implicit_lifetime}@ 202302L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_invocable}@ 201703L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_layout_compatible}@ 201907L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_nothrow_convertible}@ 201806L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_null_pointer}@ 201309L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_pointer_interconvertible}@ 201907L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_scoped_enum}@ 202011L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_is_sufficiently_aligned}@ 202411L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_is_swappable}@ 201603L // freestanding, also in \libheader{type_traits} -#define @\defnlibxname{cpp_lib_is_within_lifetime}@ 202306L // also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_is_virtual_base_of}@ 202406L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_is_within_lifetime}@ 202306L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_jthread}@ 201911L // also in \libheader{stop_token}, \libheader{thread} #define @\defnlibxname{cpp_lib_latch}@ 201907L // also in \libheader{latch} #define @\defnlibxname{cpp_lib_launder}@ 201606L // freestanding, also in \libheader{new} +#define @\defnlibxname{cpp_lib_linalg}@ 202412L // also in \libheader{linalg} #define @\defnlibxname{cpp_lib_list_remove_return_type}@ 201806L // also in \libheader{forward_list}, \libheader{list} #define @\defnlibxname{cpp_lib_logical_traits}@ 201510L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_make_from_tuple}@ 201606L // freestanding, also in \libheader{tuple} @@ -695,7 +740,7 @@ #define @\defnlibxname{cpp_lib_map_try_emplace}@ 201411L // also in \libheader{map} #define @\defnlibxname{cpp_lib_math_constants}@ 201907L // also in \libheader{numbers} #define @\defnlibxname{cpp_lib_math_special_functions}@ 201603L // also in \libheader{cmath} -#define @\defnlibxname{cpp_lib_mdspan}@ 202207L // also in \libheader{mdspan} +#define @\defnlibxname{cpp_lib_mdspan}@ 202406L // freestanding, also in \libheader{mdspan} #define @\defnlibxname{cpp_lib_memory_resource}@ 201603L // also in \libheader{memory_resource} #define @\defnlibxname{cpp_lib_modules}@ 202207L // freestanding #define @\defnlibxname{cpp_lib_move_iterator_concept}@ 202207L // freestanding, also in \libheader{iterator} @@ -708,51 +753,65 @@ #define @\defnlibxname{cpp_lib_not_fn}@ 202306L // freestanding, also in \libheader{functional} #define @\defnlibxname{cpp_lib_null_iterators}@ 201304L // freestanding, also in \libheader{iterator} #define @\defnlibxname{cpp_lib_optional}@ 202110L // also in \libheader{optional} -#define @\defnlibxname{cpp_lib_out_ptr}@ 202106L // also in \libheader{memory} +#define @\defnlibxname{cpp_lib_optional_range_support}@ 202406L // freestanding, also in \libheader{optional} +#define @\defnlibxname{cpp_lib_out_ptr}@ 202311L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_parallel_algorithm}@ 201603L // also in \libheader{algorithm}, \libheader{numeric} +#define @\defnlibxname{cpp_lib_philox_engine}@ 202406L // also in \libheader{random} +#define @\defnlibxname{cpp_lib_polymorphic}@ 202502L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_polymorphic_allocator}@ 201902L // also in \libheader{memory_resource} -#define @\defnlibxname{cpp_lib_print}@ 202207L // also in \libheader{print}, \libheader{ostream} +#define @\defnlibxname{cpp_lib_print}@ 202406L // also in \libheader{print}, \libheader{ostream} #define @\defnlibxname{cpp_lib_quoted_string_io}@ 201304L // also in \libheader{iomanip} -#define @\defnlibxname{cpp_lib_ranges}@ 202302L +#define @\defnlibxname{cpp_lib_ranges}@ 202406L // also in \libheader{algorithm}, \libheader{functional}, \libheader{iterator}, \libheader{memory}, \libheader{ranges} -#define @\defnlibxname{cpp_lib_ranges_as_const}@ 202207L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_as_const}@ 202311L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_as_rvalue}@ 202207L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_cache_latest}@ 202411L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_cartesian_product}@ 202207L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_concat}@ 202403L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_contains}@ 202207L // also in \libheader{algorithm} -#define @\defnlibxname{cpp_lib_ranges_enumerate}@ 202302L // also in \libheader{ranges}, \libheader{version} +#define @\defnlibxname{cpp_lib_ranges_enumerate}@ 202302L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_find_last}@ 202207L // also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_ranges_fold}@ 202207L // also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_ranges_generate_random}@ 202403L // also in \libheader{random} #define @\defnlibxname{cpp_lib_ranges_iota}@ 202202L // also in \libheader{numeric} #define @\defnlibxname{cpp_lib_ranges_join_with}@ 202202L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_repeat}@ 202207L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_reserve_hint}@ 202502L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_slide}@ 202202L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_starts_ends_with}@ 202106L // also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_ranges_stride}@ 202207L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_to_container}@ 202202L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_to_input}@ 202502L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_zip}@ 202110L // freestanding, also in \libheader{ranges}, \libheader{tuple}, \libheader{utility} -#define @\defnlibxname{cpp_lib_ratio}@ 202306L // also in \libheader{ratio} -#define @\defnlibxname{cpp_lib_raw_memory_algorithms}@ 201606L // also in \libheader{memory} +#define @\defnlibxname{cpp_lib_ratio}@ 202306L // freestanding, also in \libheader{ratio} +#define @\defnlibxname{cpp_lib_raw_memory_algorithms}@ 202411L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_rcu}@ 202306L // also in \libheader{rcu} #define @\defnlibxname{cpp_lib_reference_from_temporary}@ 202202L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_reference_wrapper}@ 202403L // freestanding, also in \libheader{functional} #define @\defnlibxname{cpp_lib_remove_cvref}@ 201711L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_result_of_sfinae}@ 201210L // freestanding, also in \libheader{functional}, \libheader{type_traits} #define @\defnlibxname{cpp_lib_robust_nonmodifying_seq_ops}@ 201304L // also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_sample}@ 201603L // also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_saturation_arithmetic}@ 202311L // also in \libheader{numeric} #define @\defnlibxname{cpp_lib_scoped_lock}@ 201703L // also in \libheader{mutex} #define @\defnlibxname{cpp_lib_semaphore}@ 201907L // also in \libheader{semaphore} +#define @\defnlibxname{cpp_lib_senders}@ 202406L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_shared_mutex}@ 201505L // also in \libheader{shared_mutex} #define @\defnlibxname{cpp_lib_shared_ptr_arrays}@ 201707L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_shared_ptr_weak_type}@ 201606L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_shared_timed_mutex}@ 201402L // also in \libheader{shared_mutex} #define @\defnlibxname{cpp_lib_shift}@ 202202L // also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_simd}@ 202502L // also in \libheader{simd} +#define @\defnlibxname{cpp_lib_simd_complex}@ 202502L // also in \libheader{simd} #define @\defnlibxname{cpp_lib_smart_ptr_for_overwrite}@ 202002L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_smart_ptr_owner_equality}@ 202306L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_source_location}@ 201907L // freestanding, also in \libheader{source_location} -#define @\defnlibxname{cpp_lib_span}@ 202002L // also in \libheader{span} +#define @\defnlibxname{cpp_lib_span}@ 202311L // freestanding, also in \libheader{span} +#define @\defnlibxname{cpp_lib_span_initializer_list}@ 202311L // freestanding, also in \libheader{span} #define @\defnlibxname{cpp_lib_spanstream}@ 202106L // also in \libheader{spanstream} #define @\defnlibxname{cpp_lib_ssize}@ 201902L // freestanding, also in \libheader{iterator} #define @\defnlibxname{cpp_lib_sstream_from_string_view}@ 202306L // also in \libheader{sstream} @@ -763,21 +822,23 @@ #define @\defnlibxname{cpp_lib_string_contains}@ 202011L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_string_resize_and_overwrite}@ 202110L // also in \libheader{string} #define @\defnlibxname{cpp_lib_string_udls}@ 201304L // also in \libheader{string} -#define @\defnlibxname{cpp_lib_string_view}@ 201803L // also in \libheader{string}, \libheader{string_view} -#define @\defnlibxname{cpp_lib_submdspan}@ 202306L // also in \libheader{mdspan} +#define @\defnlibxname{cpp_lib_string_view}@ 202403L // also in \libheader{string}, \libheader{string_view} +#define @\defnlibxname{cpp_lib_submdspan}@ 202411L // freestanding, also in \libheader{mdspan} #define @\defnlibxname{cpp_lib_syncbuf}@ 201803L // also in \libheader{syncstream} #define @\defnlibxname{cpp_lib_text_encoding}@ 202306L // also in \libheader{text_encoding} #define @\defnlibxname{cpp_lib_three_way_comparison}@ 201907L // freestanding, also in \libheader{compare} #define @\defnlibxname{cpp_lib_to_address}@ 201711L // freestanding, also in \libheader{memory} -#define @\defnlibxname{cpp_lib_to_array}@ 201907L // also in \libheader{array} +#define @\defnlibxname{cpp_lib_to_array}@ 201907L // freestanding, also in \libheader{array} #define @\defnlibxname{cpp_lib_to_chars}@ 202306L // also in \libheader{charconv} #define @\defnlibxname{cpp_lib_to_string}@ 202306L // also in \libheader{string} #define @\defnlibxname{cpp_lib_to_underlying}@ 202102L // freestanding, also in \libheader{utility} #define @\defnlibxname{cpp_lib_transformation_trait_aliases}@ 201304L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_transparent_operators}@ 201510L // freestanding, also in \libheader{memory}, \libheader{functional} +#define @\defnlibxname{cpp_lib_trivially_relocatable}@ 202502L + // freestanding, also in \libheader{memory}, \libheader{type_traits} #define @\defnlibxname{cpp_lib_tuple_element_t}@ 201402L // freestanding, also in \libheader{tuple} -#define @\defnlibxname{cpp_lib_tuple_like}@ 202207L +#define @\defnlibxname{cpp_lib_tuple_like}@ 202311L // also in \libheader{utility}, \libheader{tuple}, \libheader{map}, \libheader{unordered_map} #define @\defnlibxname{cpp_lib_tuples_by_type}@ 201304L // freestanding, also in \libheader{utility}, \libheader{tuple} #define @\defnlibxname{cpp_lib_type_identity}@ 201806L // freestanding, also in \libheader{type_traits} @@ -790,6 +851,25 @@ #define @\defnlibxname{cpp_lib_void_t}@ 201411L // freestanding, also in \libheader{type_traits} \end{codeblock} +\pnum +Additionally, each of the following macros is defined in a hardened implementation: +\begin{codeblock} +#define @\defnlibxname{cpp_lib_hardened_array}@ 202502L // also in \libheader{array} +#define @\defnlibxname{cpp_lib_hardened_basic_string}@ 202502L // also in \libheader{string} +#define @\defnlibxname{cpp_lib_hardened_basic_string_view}@ 202502L // also in \libheader{string_view} +#define @\defnlibxname{cpp_lib_hardened_bitset}@ 202502L // also in \libheader{bitset} +#define @\defnlibxname{cpp_lib_hardened_deque}@ 202502L // also in \libheader{deque} +#define @\defnlibxname{cpp_lib_hardened_expected}@ 202502L // also in \libheader{expected} +#define @\defnlibxname{cpp_lib_hardened_forward_list}@ 202502L // also in \libheader{forward_list} +#define @\defnlibxname{cpp_lib_hardened_inplace_vector}@ 202502L // also in \libheader{inplace_vector} +#define @\defnlibxname{cpp_lib_hardened_list}@ 202502L // also in \libheader{list} +#define @\defnlibxname{cpp_lib_hardened_mdspan}@ 202502L // also in \libheader{mdspan} +#define @\defnlibxname{cpp_lib_hardened_optional}@ 202502L // also in \libheader{optional} +#define @\defnlibxname{cpp_lib_hardened_span}@ 202502L // also in \libheader{span} +#define @\defnlibxname{cpp_lib_hardened_valarray}@ 202502L // also in \libheader{valarray} +#define @\defnlibxname{cpp_lib_hardened_vector}@ 202502L // also in \libheader{vector} +\end{codeblock} + \pnum The macro \xname{cpp_lib_freestanding_operator_new} is defined to the integer literal \tcode{202306L} @@ -802,6 +882,11 @@ Freestanding implementations should only define a macro from \libheader{version} if the implementation provides the corresponding facility in its entirety. +\pnum +\recommended +A non-hardened implementation should not define macros from \libheader{version} +required for hardened implementations. + \rSec2[limits.syn]{Header \tcode{} synopsis} \indexheader{limits}% @@ -990,6 +1075,11 @@ \pnum \indextext{signal-safe!\idxcode{numeric_limits} members}% Each member function defined in this subclause is signal-safe\iref{support.signal}. +\begin{note} +\indextext{LIA-1}% +The arithmetic specification described in ISO/IEC 10967-1:2012 is +commonly termed LIA-1. +\end{note} \indexlibrarymember{min}{numeric_limits}% \begin{itemdecl} @@ -1200,16 +1290,14 @@ \pnum Measure of the maximum rounding error. \begin{footnote} -Rounding error is described in -LIA-1 -Section 5.2.4 and +Rounding error is described in ISO/IEC 10967-1:2012 Section 5.2.4 and Annex C Rationale Section C.5.2.4 --- Rounding and rounding constants. \end{footnote} \end{itemdescr} \indexlibrarymember{min_exponent}{numeric_limits}% \begin{itemdecl} -static constexpr int min_exponent; +static constexpr int min_exponent; \end{itemdecl} \begin{itemdescr} @@ -1229,7 +1317,7 @@ \indexlibrarymember{min_exponent10}{numeric_limits}% \begin{itemdecl} -static constexpr int min_exponent10; +static constexpr int min_exponent10; \end{itemdecl} \begin{itemdescr} @@ -1247,7 +1335,7 @@ \indexlibrarymember{max_exponent}{numeric_limits}% \begin{itemdecl} -static constexpr int max_exponent; +static constexpr int max_exponent; \end{itemdecl} \begin{itemdescr} @@ -1267,7 +1355,7 @@ \indexlibrarymember{max_exponent10}{numeric_limits}% \begin{itemdecl} -static constexpr int max_exponent10; +static constexpr int max_exponent10; \end{itemdecl} \begin{itemdescr} @@ -1312,7 +1400,7 @@ \tcode{true} if the type has a representation for a quiet (non-signaling) ``Not a Number''. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1334,7 +1422,7 @@ \pnum \tcode{true} if the type has a representation for a signaling ``Not a Number''. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1356,7 +1444,7 @@ \pnum Representation of positive infinity, if available. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1375,7 +1463,7 @@ \pnum Representation of a quiet ``Not a Number'', if available. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1394,7 +1482,7 @@ \pnum Representation of a signaling ``Not a Number'', if available. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1414,7 +1502,7 @@ \pnum Minimum positive subnormal value, if available. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} Otherwise, minimum positive normalized value. @@ -1429,9 +1517,9 @@ \begin{itemdescr} \pnum -\tcode{true} if and only if the type adheres to ISO/IEC/IEEE 60559. +\tcode{true} if and only if the type adheres to \IsoFloatUndated{}. \begin{footnote} -ISO/IEC/IEEE 60559:2020 is the same as IEEE 754-2019. +\IsoFloatUndated{}:2020 is the same as IEEE 754-2019. \end{footnote} \begin{note} The value is \tcode{true} for any of the types @@ -1452,7 +1540,7 @@ \pnum \tcode{true} if the set of values representable by the type is finite. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \begin{note} All fundamental types\iref{basic.fundamental} are bounded. This member would be \tcode{false} for arbitrary @@ -1472,7 +1560,7 @@ \pnum \tcode{true} if the type is modulo. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} A type is modulo if, for any operation involving \tcode{+}, \tcode{-}, or \tcode{*} on values of that type whose result would fall outside the range @@ -1501,7 +1589,7 @@ if, at the start of the program, there exists a value of the type that would cause an arithmetic operation using that value to trap. \begin{footnote} -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1519,8 +1607,8 @@ if tinyness is detected before rounding. \begin{footnote} Refer to -ISO/IEC/IEEE 60559. -Required by LIA-1. +\IsoFloatUndated{}. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1537,7 +1625,7 @@ The rounding style for the type. \begin{footnote} Equivalent to \tcode{FLT_ROUNDS}. -Required by LIA-1. +Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1590,9 +1678,9 @@ static constexpr int max_exponent = +128; static constexpr int max_exponent10 = + 38; - static constexpr bool has_infinity = true; - static constexpr bool has_quiet_NaN = true; - static constexpr bool has_signaling_NaN = true; + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; static constexpr float infinity() noexcept { return @\textit{value}@; } static constexpr float quiet_NaN() noexcept { return @\textit{value}@; } @@ -1618,45 +1706,45 @@ \indexlibraryglobal{numeric_limits}% \begin{codeblock} namespace std { - template<> class numeric_limits { - public: - static constexpr bool is_specialized = true; - static constexpr bool min() noexcept { return false; } - static constexpr bool max() noexcept { return true; } - static constexpr bool lowest() noexcept { return false; } - - static constexpr int digits = 1; - static constexpr int digits10 = 0; - static constexpr int max_digits10 = 0; - - static constexpr bool is_signed = false; - static constexpr bool is_integer = true; - static constexpr bool is_exact = true; - static constexpr int radix = 2; - static constexpr bool epsilon() noexcept { return 0; } - static constexpr bool round_error() noexcept { return 0; } - - static constexpr int min_exponent = 0; - static constexpr int min_exponent10 = 0; - static constexpr int max_exponent = 0; - static constexpr int max_exponent10 = 0; - - static constexpr bool has_infinity = false; - static constexpr bool has_quiet_NaN = false; - static constexpr bool has_signaling_NaN = false; - static constexpr bool infinity() noexcept { return 0; } - static constexpr bool quiet_NaN() noexcept { return 0; } - static constexpr bool signaling_NaN() noexcept { return 0; } - static constexpr bool denorm_min() noexcept { return 0; } - - static constexpr bool is_iec559 = false; - static constexpr bool is_bounded = true; - static constexpr bool is_modulo = false; - - static constexpr bool traps = false; - static constexpr bool tinyness_before = false; - static constexpr float_round_style round_style = round_toward_zero; - }; + template<> class numeric_limits { + public: + static constexpr bool is_specialized = true; + static constexpr bool min() noexcept { return false; } + static constexpr bool max() noexcept { return true; } + static constexpr bool lowest() noexcept { return false; } + + static constexpr int digits = 1; + static constexpr int digits10 = 0; + static constexpr int max_digits10 = 0; + + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr int radix = 2; + static constexpr bool epsilon() noexcept { return 0; } + static constexpr bool round_error() noexcept { return 0; } + + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr bool infinity() noexcept { return 0; } + static constexpr bool quiet_NaN() noexcept { return 0; } + static constexpr bool signaling_NaN() noexcept { return 0; } + static constexpr bool denorm_min() noexcept { return 0; } + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + static constexpr float_round_style round_style = round_toward_zero; + }; } \end{codeblock} @@ -1847,6 +1935,34 @@ \indexlibraryglobal{uint_least64_t}% \indexlibraryglobal{uintmax_t}% \indexlibraryglobal{uintptr_t}% +\indexlibraryglobal{INTN_MIN}% +\indexlibraryglobal{INTN_MAX}% +\indexlibraryglobal{UINTN_MAX}% +\indexlibraryglobal{INT_FASTN_MIN}% +\indexlibraryglobal{INT_FASTN_MAX}% +\indexlibraryglobal{UINT_FASTN_MAX}% +\indexlibraryglobal{INT_LEASTN_MIN}% +\indexlibraryglobal{INT_LEASTN_MAX}% +\indexlibraryglobal{UINT_LEASTN_MAX}% +\indexlibraryglobal{INTMAX_MIN}% +\indexlibraryglobal{INTMAX_MAX}% +\indexlibraryglobal{UINTMAX_MAX}% +\indexlibraryglobal{INTPTR_MIN}% +\indexlibraryglobal{INTPTR_MAX}% +\indexlibraryglobal{UINTPTR_MAX}% +\indexlibraryglobal{PTRDIFF_MIN}% +\indexlibraryglobal{PTRDIFF_MAX}% +\indexlibraryglobal{SIZE_MAX}% +\indexlibraryglobal{SIG_ATOMIC_MIN}% +\indexlibraryglobal{SIG_ATOMIC_MAX}% +\indexlibraryglobal{WCHAR_MAX}% +\indexlibraryglobal{WCHAR_MIN}% +\indexlibraryglobal{WINT_MIN}% +\indexlibraryglobal{WINT_MAX}% +\indexlibraryglobal{INTN_C}% +\indexlibraryglobal{UINTN_C}% +\indexlibraryglobal{INTMAX_C}% +\indexlibraryglobal{UINTMAX_C}% \begin{codeblock} // all freestanding namespace std { @@ -2012,7 +2128,7 @@ \pnum \remarks -The program is terminated without executing destructors for objects of automatic, +The program is terminated without executing destructors for objects with automatic, thread, or static storage duration and without calling functions passed to \tcode{atexit()}\iref{basic.start.term}. \indextext{signal-safe!\idxcode{_Exit}}% @@ -2243,7 +2359,7 @@ new_handler set_new_handler(new_handler new_p) noexcept; // \ref{ptr.launder}, pointer optimization barrier - template [[nodiscard]] constexpr T* launder(T* p) noexcept; + template constexpr T* launder(T* p) noexcept; // \ref{hardware.interference}, hardware interference size inline constexpr size_t hardware_destructive_interference_size = @\impdef{}@; @@ -2251,11 +2367,10 @@ } // \ref{new.delete}, storage allocation and deallocation -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, - const std::nothrow_t&) noexcept; +void* operator new(std::size_t size); +void* operator new(std::size_t size, std::align_val_t alignment); +void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; void operator delete(void* ptr) noexcept; void operator delete(void* ptr, std::size_t size) noexcept; @@ -2264,11 +2379,11 @@ void operator delete(void* ptr, const std::nothrow_t&) noexcept; void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new[](std::size_t size); -[[nodiscard]] void* operator new[](std::size_t size, std::align_val_t alignment); -[[nodiscard]] void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new[](std::size_t size, std::align_val_t alignment, - const std::nothrow_t&) noexcept; +void* operator new[](std::size_t size); +void* operator new[](std::size_t size, std::align_val_t alignment); +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +void* operator new[](std::size_t size, std::align_val_t alignment, + const std::nothrow_t&) noexcept; void operator delete[](void* ptr) noexcept; void operator delete[](void* ptr, std::size_t size) noexcept; @@ -2277,8 +2392,8 @@ void operator delete[](void* ptr, const std::nothrow_t&) noexcept; void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new (std::size_t size, void* ptr) noexcept; -[[nodiscard]] void* operator new[](std::size_t size, void* ptr) noexcept; +constexpr void* operator new (std::size_t size, void* ptr) noexcept; +constexpr void* operator new[](std::size_t size, void* ptr) noexcept; void operator delete (void* ptr, void*) noexcept; void operator delete[](void* ptr, void*) noexcept; \end{codeblock} @@ -2315,18 +2430,12 @@ If any of the default versions of the replaceable global allocation functions meet the requirements of a hosted implementation, they all should. -\newcommand{\replaceabledesc}[1]{% -A \Cpp{} program may define functions with #1 of these function signatures, -and thereby displace the default versions defined by the -\Cpp{} standard library.% -} - \rSec3[new.delete.single]{Single-object forms} \indexlibrarymember{new}{operator}% \begin{itemdecl} -[[nodiscard]] void* operator new(std::size_t size); -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); +void* operator new(std::size_t size); +void* operator new(std::size_t size, std::align_val_t alignment); \end{itemdecl} \begin{itemdescr} @@ -2341,10 +2450,6 @@ The second form is called for a type with new-extended alignment, and the first form is called otherwise. -\pnum -\replaceable -\replaceabledesc{either} - \pnum \required Return a non-null pointer to suitably aligned storage\iref{basic.stc.dynamic}, @@ -2381,13 +2486,16 @@ \tcode{new_handler} function does not return. \end{itemize} + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. \end{itemdescr} \indexlibrarymember{new}{operator}% \begin{itemdecl} -[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, - const std::nothrow_t&) noexcept; +void* operator new(std::size_t size, const std::nothrow_t&) noexcept; +void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; \end{itemdecl} \begin{itemdescr} @@ -2400,10 +2508,6 @@ \tcode{bad_alloc} exception. -\pnum -\replaceable -\replaceabledesc{either} - \pnum \required Return a non-null pointer to suitably aligned storage\iref{basic.stc.dynamic}, @@ -2431,6 +2535,10 @@ T* p2 = new(nothrow) T; // returns \keyword{nullptr} if it fails \end{codeblock} \end{example} + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. \end{itemdescr} \indexlibrarymember{delete}{operator}% @@ -2473,20 +2581,6 @@ \grammarterm{delete-expression}\iref{expr.delete} to render the value of \tcode{ptr} invalid. -\pnum -\replaceable -\replaceabledesc{any} -If a function without a \tcode{size} parameter is defined, -the program should also define -the corresponding function with a \tcode{size} parameter. -If a function with a \tcode{size} parameter is defined, -the program shall also define -the corresponding version without the \tcode{size} parameter. -\begin{note} -The default behavior below might change in the future, which will require -replacing both deallocation functions when replacing the allocation function. -\end{note} - \pnum \required A call to an \tcode{operator delete} @@ -2507,7 +2601,7 @@ forward their other parameters to the corresponding function without a \tcode{size} parameter. \begin{note} -See the note in the above \replaceable paragraph. +See the note in the below \remarks paragraph. \end{note} \pnum @@ -2529,6 +2623,22 @@ or \tcode{realloc}, declared in \libheaderref{cstdlib}. +This function is replaceable\iref{dcl.fct.def.replace}. +If a replacement function +without a \tcode{size} parameter +is defined by the program, +the program should also define the corresponding +function with a \tcode{size} parameter. +If a replacement function +with a \tcode{size} parameter +is defined by the program, +the program shall also define the corresponding +version without the \tcode{size} parameter. +\begin{note} +The default behavior above might change in the future, +which will require replacing both deallocation functions +when replacing the allocation function. +\end{note} \end{itemdescr} \indexlibrarymember{delete}{operator}% @@ -2567,23 +2677,23 @@ when the constructor invoked from a nothrow placement version of the \grammarterm{new-expression} throws an exception. -\pnum -\replaceable -\replaceabledesc{either} - \pnum \default Calls \tcode{operator delete(ptr)}, or \tcode{operator delete(ptr, alignment)}, respectively. + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. \end{itemdescr} \rSec3[new.delete.array]{Array forms} \indexlibrarymember{new}{operator}% \begin{itemdecl} -[[nodiscard]] void* operator new[](std::size_t size); -[[nodiscard]] void* operator new[](std::size_t size, std::align_val_t alignment); +void* operator new[](std::size_t size); +void* operator new[](std::size_t size, std::align_val_t alignment); \end{itemdecl} \begin{itemdescr} @@ -2615,10 +2725,6 @@ to obtain space to store supplemental information. \end{footnote} -\pnum -\replaceable -\replaceabledesc{either} - \pnum \required Same as for @@ -2632,13 +2738,16 @@ or \tcode{operator new(size, alignment)}, respectively. + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. \end{itemdescr} \indexlibrarymember{new}{operator}% \begin{itemdecl} -[[nodiscard]] void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; -[[nodiscard]] void* operator new[](std::size_t size, std::align_val_t alignment, - const std::nothrow_t&) noexcept; +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; +void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; \end{itemdecl} \begin{itemdescr} @@ -2651,10 +2760,6 @@ \tcode{bad_alloc} exception. -\pnum -\replaceable -\replaceabledesc{either} - \pnum \required Return a non-null pointer to suitably aligned storage\iref{basic.stc.dynamic}, @@ -2674,6 +2779,10 @@ If the call returns normally, returns the result of that call. Otherwise, returns a null pointer. + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. \end{itemdescr} \indexlibrarymember{delete}{operator}% @@ -2716,20 +2825,6 @@ \grammarterm{delete-expression} to render the value of \tcode{ptr} invalid. -\pnum -\replaceable -\replaceabledesc{any} -If a function without a \tcode{size} parameter is defined, -the program should also define -the corresponding function with a \tcode{size} parameter. -If a function with a \tcode{size} parameter is defined, -the program shall also define -the corresponding version without the \tcode{size} parameter. -\begin{note} -The default behavior below might change in the future, which will require -replacing both deallocation functions when replacing the allocation function. -\end{note} - \pnum \required A call to an \tcode{operator delete[]} @@ -2752,6 +2847,25 @@ The functions that do not have a \tcode{size} parameter forward their parameters to the corresponding \tcode{operator delete} (single-object) function. + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. +If a replacement function +without a \tcode{size} parameter +is defined by the program, +the program should also define the corresponding +function with a \tcode{size} parameter. +If a replacement function +with a \tcode{size} parameter +is defined by the program, +the program shall also define the corresponding +version without the \tcode{size} parameter. +\begin{note} +The default behavior above might change in the future, +which will require replacing both deallocation functions +when replacing the allocation function. +\end{note} \end{itemdescr} \indexlibrarymember{delete}{operator}% @@ -2790,15 +2904,15 @@ when the constructor invoked from a nothrow placement version of the array \grammarterm{new-expression} throws an exception. -\pnum -\replaceable -\replaceabledesc{either} - \pnum \default Calls \tcode{operator delete[](ptr)}, or \tcode{operator delete[](ptr, alignment)}, respectively. + +\pnum +\remarks +This function is replaceable\iref{dcl.fct.def.replace}. \end{itemdescr} \rSec3[new.delete.placement]{Non-allocating forms} @@ -2811,7 +2925,7 @@ \indexlibrarymember{new}{operator}% \begin{itemdecl} -[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept; +constexpr void* operator new(std::size_t size, void* ptr) noexcept; \end{itemdecl} \begin{itemdescr} @@ -2836,7 +2950,7 @@ \indexlibrarymember{new}{operator}% \begin{itemdecl} -[[nodiscard]] void* operator new[](std::size_t size, void* ptr) noexcept; +constexpr void* operator new[](std::size_t size, void* ptr) noexcept; \end{itemdecl} \begin{itemdescr} @@ -2913,7 +3027,7 @@ class bad_alloc : public exception { public: // see \ref{exception} for the specification of the special member functions - const char* what() const noexcept override; + constexpr const char* what() const noexcept override; }; } \end{codeblock} @@ -2926,7 +3040,7 @@ \indexlibrarymember{what}{bad_alloc}% \begin{itemdecl} -const char* what() const noexcept override; +constexpr const char* what() const noexcept override; \end{itemdecl} \begin{itemdescr} @@ -2944,7 +3058,7 @@ class bad_array_new_length : public bad_alloc { public: // see \ref{exception} for the specification of the special member functions - const char* what() const noexcept override; + constexpr const char* what() const noexcept override; }; } \end{codeblock} @@ -2957,7 +3071,7 @@ \indexlibrarymember{what}{bad_array_new_length}% \begin{itemdecl} -const char* what() const noexcept override; +constexpr const char* what() const noexcept override; \end{itemdecl} \begin{itemdescr} @@ -3043,7 +3157,7 @@ \indexlibraryglobal{launder}% \begin{itemdecl} -template [[nodiscard]] constexpr T* launder(T* p) noexcept; +template constexpr T* launder(T* p) noexcept; \end{itemdecl} \begin{itemdescr} @@ -3152,12 +3266,16 @@ \rSec2[support.rtti.general]{General} \pnum -The header \libheaderdef{typeinfo} defines a +The header \libheaderref{typeinfo} defines a type associated with type information generated by the implementation. It also defines two types for reporting dynamic type identification errors. +The header \libheaderrefx{typeindex}{type.index.synopsis} defines +a wrapper type for use as an index type in associative containers\iref{associative} +and in unordered associative containers\iref{unord}. \rSec2[typeinfo.syn]{Header \tcode{} synopsis} +\indexheader{typeinfo}% \indexlibraryglobal{type_info}% \indexlibraryglobal{bad_cast}% \indexlibraryglobal{bad_typeid}% @@ -3183,8 +3301,8 @@ size_t hash_code() const noexcept; const char* name() const noexcept; - type_info(const type_info&) = delete; // cannot be copied - type_info& operator=(const type_info&) = delete; // cannot be copied + type_info(const type_info&) = delete; + type_info& operator=(const type_info&) = delete; }; } \end{codeblock} @@ -3278,7 +3396,7 @@ class bad_cast : public exception { public: // see \ref{exception} for the specification of the special member functions - const char* what() const noexcept override; + constexpr const char* what() const noexcept override; }; } \end{codeblock} @@ -3294,7 +3412,7 @@ \indexlibrarymember{what}{bad_cast}% \begin{itemdecl} -const char* what() const noexcept override; +constexpr const char* what() const noexcept override; \end{itemdecl} \begin{itemdescr} @@ -3312,7 +3430,7 @@ class bad_typeid : public exception { public: // see \ref{exception} for the specification of the special member functions - const char* what() const noexcept override; + constexpr const char* what() const noexcept override; }; } \end{codeblock} @@ -3328,7 +3446,7 @@ \indexlibrarymember{what}{bad_typeid}% \begin{itemdecl} -const char* what() const noexcept override; +constexpr const char* what() const noexcept override; \end{itemdecl} \begin{itemdescr} @@ -3337,6 +3455,166 @@ An \impldef{return value of \tcode{bad_typeid::what}} \ntbs{}. \end{itemdescr} +\rSec2[type.index.synopsis]{Header \tcode{} synopsis} + +\indexheader{typeindex}% +\begin{codeblock} +#include // see \ref{compare.syn} + +namespace std { + class type_index; + template struct hash; + template<> struct hash; +} +\end{codeblock} + +\rSec2[type.index]{Class \tcode{type_index}} + +\indexlibraryglobal{type_index}% +\begin{codeblock} +namespace std { + class type_index { + 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; + strong_ordering operator<=>(const type_index& rhs) const noexcept; + size_t hash_code() const noexcept; + const char* name() const noexcept; + + private: + const type_info* target; // \expos + // Note that the use of a pointer here, rather than a reference, + // means that the default copy/move constructor and assignment + // operators will be provided and work as expected. + }; +} +\end{codeblock} + +\pnum +The class \tcode{type_index} provides a simple wrapper for +\tcode{type_info} which can be used as an index type in associative +containers\iref{associative} and in unordered associative +containers\iref{unord}. + +\indexlibraryctor{type_index}% +\begin{itemdecl} +type_index(const type_info& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs a \tcode{type_index} object, the equivalent of \tcode{target = \&rhs}. +\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; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{target->before(*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{rhs.target->before(*target)}. +\end{itemdescr} + +\indexlibrarymember{operator<=}{type_index}% +\begin{itemdecl} +bool operator<=(const type_index& rhs) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!rhs.target->before(*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->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; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{target->hash_code()}. +\end{itemdescr} + +\indexlibrarymember{name}{type_index}% +\begin{itemdecl} +const char* name() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{target->name()}. +\end{itemdescr} + +\indexlibrarymember{hash}{type_index}% +\begin{itemdecl} +template<> struct hash; +\end{itemdecl} + +\begin{itemdescr} +\pnum +For an object \tcode{index} of type \tcode{type_index}, +\tcode{hash()(index)} shall evaluate to the same result as \tcode{index.hash_code()}. +\end{itemdescr} + \rSec1[support.srcloc]{Source location} \rSec2[source.location.syn]{Header \tcode{} synopsis} @@ -3473,7 +3751,7 @@ \pnum \remarks Any call to \tcode{current} that appears -as a default member initializer\iref{class.mem}, or +as a default member initializer\iref{class.mem.general}, or as a subexpression thereof, should correspond to the location of the constructor definition or aggregate initialization @@ -3583,16 +3861,16 @@ terminate_handler set_terminate(terminate_handler f) noexcept; [[noreturn]] void terminate() noexcept; - int uncaught_exceptions() noexcept; + constexpr int uncaught_exceptions() noexcept; using exception_ptr = @\unspec@; - exception_ptr current_exception() noexcept; - [[noreturn]] void rethrow_exception(exception_ptr p); - template exception_ptr make_exception_ptr(E e) noexcept; + constexpr exception_ptr current_exception() noexcept; + [[noreturn]] constexpr void rethrow_exception(exception_ptr p); + template constexpr exception_ptr make_exception_ptr(E e) noexcept; - template [[noreturn]] void throw_with_nested(T&& t); - template void rethrow_if_nested(const E& e); + template [[noreturn]] constexpr void throw_with_nested(T&& t); + template constexpr void rethrow_if_nested(const E& e); } \end{codeblock} @@ -3604,11 +3882,11 @@ namespace std { class exception { public: - exception() noexcept; - exception(const exception&) noexcept; - exception& operator=(const exception&) noexcept; - virtual ~exception(); - virtual const char* what() const noexcept; + constexpr exception() noexcept; + constexpr exception(const exception&) noexcept; + constexpr exception& operator=(const exception&) noexcept; + constexpr virtual ~exception(); + constexpr virtual const char* what() const noexcept; }; } \end{codeblock} @@ -3622,7 +3900,8 @@ expressions, to report errors detected during program execution. \pnum -Each standard library class \tcode{T} that derives from class \tcode{exception} +Except where explicitly specified otherwise, +each standard library class \tcode{T} that derives from class \tcode{exception} has the following publicly accessible member functions, each of them having a non-throwing exception specification\iref{except.spec}: \begin{itemize} @@ -3640,8 +3919,8 @@ \indexlibraryctor{exception}% \indexlibrarymember{operator=}{exception}% \begin{itemdecl} -exception(const exception& rhs) noexcept; -exception& operator=(const exception& rhs) noexcept; +constexpr exception(const exception& rhs) noexcept; +constexpr exception& operator=(const exception& rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -3653,7 +3932,7 @@ \indexlibrarydtor{exception}% \begin{itemdecl} -virtual ~exception(); +constexpr virtual ~exception(); \end{itemdecl} \begin{itemdescr} @@ -3665,13 +3944,15 @@ \indexlibrarymember{what}{exception}% \begin{itemdecl} -virtual const char* what() const noexcept; +constexpr virtual const char* what() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -An \impldef{return value of \tcode{exception::what}} \ntbs{}. +An \impldef{return value of \tcode{exception::what}} \ntbs{}, +which during constant evaluation is encoded with +the ordinary literal encoding\iref{lex.ccon}. \pnum \remarks @@ -3692,7 +3973,7 @@ class bad_exception : public exception { public: // see \ref{exception} for the specification of the special member functions - const char* what() const noexcept override; + constexpr const char* what() const noexcept override; }; } \end{codeblock} @@ -3707,7 +3988,7 @@ \indexlibrarymember{what}{bad_exception}% \begin{itemdecl} -const char* what() const noexcept override; +constexpr const char* what() const noexcept override; \end{itemdecl} \begin{itemdescr} @@ -3814,13 +4095,13 @@ \indexlibraryglobal{uncaught_exceptions}% \begin{itemdecl} -int uncaught_exceptions() noexcept; +constexpr int uncaught_exceptions() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -The number of uncaught exceptions\iref{except.uncaught}. +The number of uncaught exceptions\iref{except.throw} in the current thread. \pnum \remarks @@ -3875,11 +4156,14 @@ Changes in the number of \tcode{exception_ptr} objects that refer to a particular exception do not introduce a data race. \end{note} + +\pnum +All member functions are marked \tcode{constexpr}. \end{itemdescr} \indexlibraryglobal{current_exception}% \begin{itemdecl} -exception_ptr current_exception() noexcept; +constexpr exception_ptr current_exception() noexcept; \end{itemdecl} \begin{itemdescr} @@ -3902,16 +4186,15 @@ returns an \tcode{exception_ptr} object that refers to the thrown exception or, if this is not possible, to an instance of \tcode{bad_exception}. \begin{note} -The -copy constructor of the thrown exception can also fail, so the implementation is allowed -to substitute a \tcode{bad_exception} object to avoid infinite -recursion. +The copy constructor of the thrown exception can also fail, +so the implementation can substitute a \tcode{bad_exception} object +to avoid infinite recursion. \end{note} \end{itemdescr} \indexlibraryglobal{rethrow_exception}% \begin{itemdecl} -[[noreturn]] void rethrow_exception(exception_ptr p); +[[noreturn]] constexpr void rethrow_exception(exception_ptr p); \end{itemdecl} \begin{itemdescr} @@ -3939,7 +4222,7 @@ \indexlibraryglobal{make_exception_ptr}% \begin{itemdecl} -template exception_ptr make_exception_ptr(E e) noexcept; +template constexpr exception_ptr make_exception_ptr(E e) noexcept; \end{itemdecl} \begin{itemdescr} @@ -3968,18 +4251,18 @@ namespace std { class nested_exception { public: - nested_exception() noexcept; - nested_exception(const nested_exception&) noexcept = default; - nested_exception& operator=(const nested_exception&) noexcept = default; - virtual ~nested_exception() = default; + constexpr nested_exception() noexcept; + constexpr nested_exception(const nested_exception&) noexcept = default; + constexpr nested_exception& operator=(const nested_exception&) noexcept = default; + constexpr virtual ~nested_exception() = default; // access functions - [[noreturn]] void rethrow_nested() const; - exception_ptr nested_ptr() const noexcept; + [[noreturn]] constexpr void rethrow_nested() const; + constexpr exception_ptr nested_ptr() const noexcept; }; - template [[noreturn]] void throw_with_nested(T&& t); - template void rethrow_if_nested(const E& e); + template [[noreturn]] constexpr void throw_with_nested(T&& t); + template constexpr void rethrow_if_nested(const E& e); } \end{codeblock} @@ -3996,7 +4279,7 @@ \indexlibraryctor{nested_exception}% \begin{itemdecl} -nested_exception() noexcept; +constexpr nested_exception() noexcept; \end{itemdecl} \begin{itemdescr} @@ -4007,7 +4290,7 @@ \indexlibrarymember{rethrow_nested}{nested_exception}% \begin{itemdecl} -[[noreturn]] void rethrow_nested() const; +[[noreturn]] constexpr void rethrow_nested() const; \end{itemdecl} \begin{itemdescr} @@ -4019,7 +4302,7 @@ \indexlibrarymember{nested_ptr}{nested_exception}% \begin{itemdecl} -exception_ptr nested_ptr() const noexcept; +constexpr exception_ptr nested_ptr() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -4030,7 +4313,7 @@ \indexlibrarymember{throw_with_nested}{nested_exception}% \begin{itemdecl} -template [[noreturn]] void throw_with_nested(T&& t); +template [[noreturn]] constexpr void throw_with_nested(T&& t); \end{itemdecl} \begin{itemdescr} @@ -4053,7 +4336,7 @@ \indexlibrarymember{rethrow_if_nested}{nested_exception}% \begin{itemdecl} -template void rethrow_if_nested(const E& e); +template constexpr void rethrow_if_nested(const E& e); \end{itemdecl} \begin{itemdescr} @@ -4069,6 +4352,268 @@ \end{codeblock} \end{itemdescr} +\rSec1[support.contract]{Contract-violation handling} + +\rSec2[contracts.syn]{Header \tcode{} synopsis} + +\pnum +The header \libheader{contracts} defines types +for reporting information about contract violations\iref{basic.contract.eval}. + +\indexheader{contracts} +\indexlibraryglobal{contract_violation}% +\begin{codeblock} +// all freestanding +namespace std::contracts { + + enum class assertion_kind : @\unspec@ { + pre = 1, + post = 2, + assert = 3 + }; + + enum class evaluation_semantic : @\unspec@ { + ignore = 1, + observe = 2, + enforce = 3, + quick_enforce = 4 + }; + + enum class detection_mode : @\unspec@ { + predicate_false = 1, + evaluation_exception = 2 + }; + + class contract_violation { + // no user-accessible constructor + public: + contract_violation(const contract_violation&) = delete; + contract_violation& operator=(const contract_violation&) = delete; + + @\seebelow@ ~contract_violation(); + + const char* comment() const noexcept; + contracts::detection_mode detection_mode() const noexcept; + exception_ptr evaluation_exception() const noexcept; + bool is_terminating() const noexcept; + assertion_kind kind() const noexcept; + source_location location() const noexcept; + evaluation_semantic semantic() const noexcept; + }; + + void invoke_default_contract_violation_handler(const contract_violation&); +} +\end{codeblock} + +\rSec2[support.contract.enum]{Enumerations} + +\pnum +\recommended +For all enumerations in \ref{support.contract.enum}, +if implementation-defined enumerators are provided, +they should have a minimum value of $1000$. + +\pnum +The enumerators of \tcode{assertion_kind} +correspond to +the syntactic forms of a contract assertion\iref{basic.contract.general}, +with meanings listed in Table~\ref{tab:support.contract.enum.kind}. + +\begin{floattable}{Enum \tcode{assertion_kind}}{support.contract.enum.kind} +{ll} +\topline +\lhdr{Name} & \rhdr{Meaning} \\ \capsep +\tcode{pre} & A precondition assertion \\ \rowsep +\tcode{post} & A postcondition assertion \\ \rowsep +\tcode{assert} & An \grammarterm{assertion-statement} \\ \rowsep +\end{floattable} + +\pnum +The enumerators of \tcode{evaluation_semantic} +correspond to +the evaluation semantics with which +a contract assertion may be evaluated\iref{basic.contract.eval}, +with meanings listed in Table~\ref{tab:support.contract.enum.semantic}. + +\begin{floattable}{Enum \tcode{evaluation_semantic}}{support.contract.enum.semantic} +{ll} +\topline +\lhdr{Name} & \rhdr{Meaning} \\ \capsep +\tcode{ignore} & Ignore evaluation semantic \\ \rowsep +\tcode{observe} & Observe evaluation semantic \\ \rowsep +\tcode{enforce} & Enforce evaluation semantic \\ \rowsep +\tcode{quick_enforce} & Quick-enforce evaluation semantic \\ \rowsep +\end{floattable} + +\pnum +The enumerators of \tcode{detection_mode} correspond to the manners in which a +contract violation can be identified\iref{basic.contract.eval}, with +meanings listed in \mbox{Table~\ref{tab:support.contract.enum.detection}}. + +\begin{floattable}{Enum \tcode{detection_mode}}{support.contract.enum.detection} +{lp{.6\hsize}} +\topline +\lhdr{Name} & \rhdr{Meaning} \\ \capsep +\tcode{predicate_false} & The predicate of the contract assertion evaluated to \keyword{false} or would have evaluated to \keyword{false}. \\ \rowsep +\tcode{evaluation_exception} & An uncaught exception occurred during evaluation of the contract assertion. \\ \rowsep +\end{floattable} + +\rSec2[support.contract.violation]{Class \tcode{contract_violation}} + +\pnum +\indexlibraryglobal{contract_violation}% +The class \tcode{contract_violation} +defines the type of objects used to represent +a contract violation that has been detected +during the evaluation of a contract assertion +with a particular evaluation semantic\iref{basic.contract.eval}. +Objects of this type can +be created only by the implementation. +It is +\impldef{whether \tcode{contract_violation} has a virtual destructor} +whether the destructor is virtual. + +\begin{itemdecl} +const char* comment() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An +\impldef{the contents provided in the \tcode{comment} field of \tcode{contract_violation}} +\ntmbs{} in +the ordinary literal encoding\iref{lex.charset}. + +\pnum +\recommended +The string returned +should contain a textual representation +of the predicate of the violated contract assertion +or an empty string if +storing a textual representation is undesired. +\begin{note} +The string can represent a +truncated, reformatted, or summarized rendering of the +predicate, before or after preprocessing. +\end{note} + +\end{itemdescr} + +\begin{itemdecl} +contracts::detection_mode detection_mode() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The enumerator value +corresponding to +the manner in which the contract violation was identified. + +\end{itemdescr} + +\begin{itemdecl} +exception_ptr evaluation_exception() const noexcept; +\end{itemdecl} + +\begin{itemdescr} + +\pnum +\returns +If the contract violation occurred +because the evaluation of the predicate exited via an exception, +an \tcode{exception_ptr} object that refers to +that exception or a copy of that exception; +otherwise, a null \tcode{exception_ptr} object. + +\end{itemdescr} + +\begin{itemdecl} +bool is_terminating() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\indextext{contract evaluation semantics!terminating}% +\pnum +\returns +\keyword{true} if the evaluation semantic is +a terminating semantic\iref{basic.contract.eval}; +otherwise, \tcode{false}. + +\end{itemdescr} + +\begin{itemdecl} +assertion_kind kind() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The enumerator value +corresponding to +the syntactic form of the violated contract assertion. + +\end{itemdescr} + +\begin{itemdecl} +source_location location() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{source_location} object +with +\impldef{the contents provided in the \tcode{location} field of \tcode{contract_violation}} +value. + +\pnum +\recommended +The value returned should be +a default constructed \tcode{source_location} object +or a value identifying the violated contract assertion: +\begin{itemize} +\item +When possible, +if the violated contract assertion was a precondition, +the source location of the function invocation should be returned. +\item +Otherwise, +the source location of the contract assertion should be returned. +\end{itemize} + +\end{itemdescr} + +\begin{itemdecl} +evaluation_semantic semantic() const noexcept; +\end{itemdecl} + +\begin{itemdescr} + +\pnum +\returns +The enumerator value +corresponding to +the evaluation semantic with which +the violated contract assertion was evaluated. + +\end{itemdescr} + +\rSec2[support.contract.invoke]{Invoke default handler} + +\begin{itemdecl} +void invoke_default_contract_violation_handler(const contract_violation& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Invokes the default contract-violation handler\iref{basic.contract.handler} +with the argument \tcode{v}. + +\end{itemdescr} + \rSec1[support.initlist]{Initializer lists} \rSec2[support.initlist.general]{General} @@ -4117,7 +4662,7 @@ A pair of pointers or a pointer plus a length would be obvious representations for \tcode{initializer_list}. \tcode{initializer_list} is used to implement initializer lists as specified -in~\ref{dcl.init.list}. Copying an initializer list does not copy the underlying +in~\ref{dcl.init.list}. Copying an \tcode{initializer_list} does not copy the underlying elements. \end{note} @@ -4310,7 +4855,7 @@ an argument other than a literal \tcode{0} is undefined. \pnum -For the purposes of subclause \ref{cmp.categories}, +For the purposes of \ref{cmp.categories}, \defn{substitutability} is the property that \tcode{f(a) == f(b)} is \tcode{true} whenever \tcode{a == b} is \tcode{true}, where \tcode{f} denotes a function that reads only comparison-salient state @@ -4762,7 +5307,7 @@ lvalues of types \tcode{const remove_reference_t} and \tcode{const remove_reference_t}, respectively. \tcode{T} and \tcode{U} model -\tcode{\exposconcept{partially-ordered-with}} only if: +\tcode{\exposconcept{partially-ordered-with}} only if \begin{itemize} \item \tcode{t < u}, @@ -4773,7 +5318,7 @@ \tcode{u <= t}, \tcode{u > t}, and \tcode{u >= t} - have the same domain. + have the same domain, \item \tcode{bool(t < u) == bool(u > t)} is \tcode{true}, \item @@ -4798,7 +5343,7 @@ 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: +model \tcode{\libconcept{three_way_comparable}} only if \begin{itemize} \item \tcode{(a <=> b == 0) == bool(a == b)} is \tcode{true}, @@ -4848,7 +5393,7 @@ Let \tcode{\exposid{CONVERT_TO_LVALUE}(E)} be defined as in \ref{concepts.compare.general}. \tcode{T}, \tcode{U}, and \tcode{Cat} -model \tcode{\libconcept{three_way_comparable_with}} only if: +model \tcode{\libconcept{three_way_comparable_with}} only if \begin{itemize} \item \tcode{t <=> u} and \tcode{u <=> t} have the same domain, @@ -4920,7 +5465,7 @@ 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 60559. + as specified in \IsoFloatUndated{}. \item Otherwise, \tcode{strong_ordering(compare_three_way()(E, F))} if it is a well-formed expression. @@ -5103,7 +5648,8 @@ Otherwise, if the expressions \tcode{E == F}, \tcode{E < F}, and \tcode{F < E} are all well-formed and - each of \tcode{decltype(E == F)} and \tcode{decltype(E < F)} models + each of \tcode{decltype(E == F)}, \tcode{decltype(E < F)}, and + \tcode{decltype(F < E)} models \exposconcept{boolean-testable}, \begin{codeblock} E == F ? partial_ordering::equivalent : @@ -5184,6 +5730,7 @@ \rSec3[coroutine.traits.primary]{Class template \tcode{coroutine_traits}} +\indexlibraryglobal{coroutine_traits}% \pnum The header \libheader{coroutine} defines the primary template \tcode{coroutine_traits} such that @@ -5543,6 +6090,8 @@ \rSec3[coroutine.handle.noop]{Class \tcode{coroutine_handle}} +\rSec4[coroutine.handle.noop.general]{General} + \indexlibraryglobal{coroutine_handle}% \begin{codeblock} namespace std { @@ -5757,21 +6306,16 @@ \rSec2[cstdarg.syn]{Header \tcode{} synopsis} \indexheader{cstdarg}% -\indexlibraryglobal{va_list}% -\indexlibraryglobal{va_start}% -\indexlibraryglobal{va_copy}% -\indexlibraryglobal{va_end}% -\indexlibraryglobal{va_arg}% \begin{codeblock} // all freestanding namespace std { - using va_list = @\seebelow@; + using @\libglobal{va_list}@ = @\seebelow@; } -#define va_arg(V, P) @\seebelow@ -#define va_copy(VDST, VSRC) @\seebelow@ -#define va_end(V) @\seebelow@ -#define va_start(V, P) @\seebelow@ +#define @\libmacro{va_arg}@(V, P) @\seebelow@ +#define @\libmacro{va_copy}@(VDST, VSRC) @\seebelow@ +#define @\libmacro{va_end}@(V) @\seebelow@ +#define @\libmacro{va_start}@(V, P) @\seebelow@ \end{codeblock} \pnum @@ -5779,12 +6323,11 @@ standard library header \libheader{stdarg.h}, with the following changes: \begin{itemize} \item -In lieu of the default argument promotions specified in ISO C 6.5.2.2, +In lieu of the default argument promotions specified in \IsoC{} 6.5.2.2, the definition in~\ref{expr.call} applies. \item -The restrictions that ISO C places on the second parameter to the -\indexlibraryglobal{va_start}% -\tcode{va_start} macro in header \libheader{stdarg.h} +The restrictions that C places on the second parameter to the +\libmacro{va_start} macro in header \libheader{stdarg.h} are different in this document. The parameter \tcode{parmN} @@ -5976,8 +6519,8 @@ the \defnx{C headers}{headers!C library} shown in \tref{c.headers}. The intended use of these headers is for interoperability only. It is possible that \Cpp{} source files need to include -one of these headers in order to be valid ISO C. -Source files that are not intended to also be valid ISO C +one of these headers in order to be valid C. +Source files that are not intended to also be valid C should not use any of the C headers. \begin{note} @@ -5988,7 +6531,7 @@ assuredly defines them in namespace \tcode{std}. \end{note} \begin{example} -The following source file is both valid \Cpp{} and valid ISO C. +The following source file is both valid \Cpp{} and valid C. Viewed as \Cpp{}, it declares a function with C language linkage; viewed as C it simply declares a function (and provides a prototype). \begin{codeblock} @@ -6022,16 +6565,18 @@ \libheader{stdalign.h} \\ \libheaderdef{stdarg.h} \\ \libheader{stdatomic.h} \\ +\libheader{stdbit.h} \\ \libheader{stdbool.h} \\ -\libheaderdef{stddef.h} \\ \columnbreak +\libheader{stdckdint.h} \\ +\libheaderdef{stddef.h} \\ \libheaderdef{stdint.h} \\ \libheaderdef{stdio.h} \\ \libheaderdef{stdlib.h} \\ \libheaderdef{string.h} \\ +\columnbreak \libheader{tgmath.h} \\ \libheaderdef{time.h} \\ -\columnbreak \libheaderdef{uchar.h} \\ \libheaderdef{wchar.h} \\ \libheaderdef{wctype.h} \\ @@ -6089,7 +6634,6 @@ \rSec2[stdbool.h.syn]{Header \tcode{} synopsis} \indexheader{stdbool.h}% -\indexhdr{stdbool.h}% \pnum The contents of the \Cpp{} header \libheader{stdbool.h} are the same as the C standard library header \libheader{stdbool.h}, with the following changes: @@ -6135,7 +6679,9 @@ \libheaderref{iso646.h}, \libheaderref{stdalign.h},\newline \libheaderref{stdatomic.h}, -\libheaderref{stdbool.h}, and +\libheaderref{stdbit.h}, +\libheaderref{stdbool.h}, +\libheaderref{stdckdint.h}, and\newline \libheaderref{tgmath.h}, each of which has a name of the form diff --git a/source/tables.tex b/source/tables.tex index c1f20586f0..678ec5d98b 100644 --- a/source/tables.tex +++ b/source/tables.tex @@ -48,6 +48,7 @@ % floattablebase without TableBase, used for lib2dtab2base \newenvironment{floattablebasex}[4] { + \protect\hypertarget{tab:#2}{} \begin{table}[#4] \caption{\label{tab:#2}#1 \quad [tab:#2]} \begin{center} @@ -196,6 +197,7 @@ \newenvironment{LongTable}[3] { \newcommand{\continuedcaption}{\caption[]{#1 (continued)}} + \protect\hypertarget{tab:#2}{} \begin{TableBase} \begin{longtable}{|#3|} \caption{#1 \quad [tab:#2]}\label{tab:#2} @@ -490,7 +492,7 @@ \newcommand{\bottomline}{\rowsep} \newcommand{\hdstyle}[1]{\textbf{##1}} \newcommand{\rowhdr}[1]{\hdstyle{##1}&} - \newcommand{\colhdr}[1]{\multicolumn{1}{|>{\centering}m{#6}|}{\hdstyle{##1}}} + \newcommand{\colhdr}[1]{\multicolumn{1}{>{\centering}m{#6}|}{\hdstyle{##1}}} \begin{floattablebasex} {#1}{#2} {>{\centering}m{#5}|@{}p{0.2\normalbaselineskip}@{}|m{#6}|m{#7} } diff --git a/source/templates.tex b/source/templates.tex index f107d82813..bf283e46da 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -59,11 +59,7 @@ \end{note} \pnum -The -\grammarterm{declaration} -in a -\grammarterm{template-declaration} -(if any) +The \grammarterm{declaration} in a \grammarterm{template-declaration} (if any) shall \begin{itemize} \item declare or define a function, a class, or a variable, or @@ -73,6 +69,8 @@ \item define a member template of a class or class template, or +\item be a \grammarterm{friend-type-declaration}, or + \item be a \grammarterm{deduction-guide}, or \item be an \grammarterm{alias-declaration}. @@ -123,7 +121,7 @@ \pnum In a \grammarterm{template-declaration}, -explicit specialization, or explicit instantiation the +explicit specialization, or explicit instantiation, the \grammarterm{init-declarator-list} in the declaration shall contain at most one declarator. When such a declaration is used to declare a class template, @@ -145,12 +143,26 @@ \begin{note} A template cannot have the same name as any other name bound in the same scope\iref{basic.scope.scope}, except -that a function template can share a name with non-template -functions\iref{dcl.fct} and/or function templates\iref{temp.over}. +that a function template can share a name with \grammarterm{using-declarator}s, +a type, non-template functions\iref{dcl.fct} and/or function templates\iref{temp.over}. Specializations, including partial specializations\iref{temp.spec.partial}, do not reintroduce or bind names. Their target scope is the target scope of the primary template, so all specializations of a template belong to the same scope as it does. +\begin{example} +\begin{codeblock} +void f() {} +class f {}; // OK +namespace N { + void f(int) {} +} +using N::f; // OK +template void f(long) {} // \#1, OK +template void f(long) {} // error: redefinition of \#1 +template void f(long long) {} // OK +template<> void f(long long) {} // OK, doesn't bind a name +\end{codeblock} +\end{example} \end{note} \pnum @@ -225,7 +237,10 @@ \begin{bnf} \nontermdef{template-parameter}\br type-parameter\br - parameter-declaration + parameter-declaration\br + type-tt-parameter\br + variable-tt-parameter\br + concept-tt-parameter \end{bnf} \begin{bnf} @@ -233,9 +248,7 @@ type-parameter-key \opt{\terminal{...}} \opt{identifier}\br type-parameter-key \opt{identifier} \terminal{=} type-id\br type-constraint \opt{\terminal{...}} \opt{identifier}\br - type-constraint \opt{identifier} \terminal{=} type-id\br - template-head type-parameter-key \opt{\terminal{...}} \opt{identifier}\br - template-head type-parameter-key \opt{identifier} \terminal{=} id-expression + type-constraint \opt{identifier} \terminal{=} type-id \end{bnf} \begin{bnf} @@ -250,6 +263,30 @@ \opt{nested-name-specifier} concept-name \terminal{<} \opt{template-argument-list} \terminal{>} \end{bnf} +\begin{bnf} +\nontermdef{type-tt-parameter}\br + template-head type-parameter-key \opt{\terminal{...}} \opt{identifier}\br + template-head type-parameter-key \opt{identifier} type-tt-parameter-default +\end{bnf} + +\begin{bnf} +\nontermdef{type-tt-parameter-default}\br + \terminal{=} \opt{nested-name-specifier} template-name\br + \terminal{=} nested-name-specifier \terminal{template} template-name +\end{bnf} + +\begin{bnf} +\nontermdef{variable-tt-parameter}\br + template-head \terminal{auto} \opt{\terminal{...}} \opt{identifier}\br + template-head \terminal{auto} \opt{identifier} \terminal{=} \opt{nested-name-specifier} template-name +\end{bnf} + +\begin{bnf} +\nontermdef{concept-tt-parameter}\br + \terminal{template} \terminal{<} template-parameter-list \terminal{>} \terminal{concept} \opt{\terminal{...}} \opt{identifier}\br + \terminal{template} \terminal{<} template-parameter-list \terminal{>} \terminal{concept} \opt{identifier} \terminal{=} \opt{nested-name-specifier} template-name +\end{bnf} + \indextext{component name}% The component names of a \grammarterm{type-constraint} are its \grammarterm{concept-name} and @@ -257,12 +294,81 @@ \begin{note} The \tcode{>} token following the \grammarterm{template-parameter-list} of a -\grammarterm{type-parameter} +\grammarterm{type-tt-parameter}, +\grammarterm{variable-tt-parameter}, or +\grammarterm{concept-tt-parameter} can be the product of replacing a \tcode{>>} token by two consecutive \tcode{>} tokens\iref{temp.names}. \end{note} +\pnum +%FIXME: "is" or "shall be"? i.e., what if it's not? +%FIXME: Note: we don't appear to ever define what a "template parameter" is; +%FIXME: is this supposed to be the definition for template parameter? +A template parameter is of one of the following kinds: +\begin{itemize} +\item +A \defnadj{type}{template parameter} is +a template parameter introduced by a \grammarterm{type-parameter}. +\item +A \defnadj{constant}{template parameter} is +a template parameter introduced by a \grammarterm{parameter-declaration}. +\item +A \defnadj{type template}{template parameter} is +a template parameter introduced by a \grammarterm{type-tt-parameter}. +\item +A \defnadj{variable template}{template parameter} is +a template parameter introduced by a \grammarterm{variable-tt-parameter}. +\item +A \defnadj{concept}{template parameter} is +a template parameter introduced by a \grammarterm{concept-tt-parameter}. +\end{itemize} + +\pnum +Type template template parameters, +variable template template parameters, and +concept template parameters +are collectively referred to as \defnadj{template}{template parameters}. + +\pnum +A concept template parameter shall not have +associated constraints\iref{temp.constr.decl}. + +\pnum +If a \grammarterm{template-parameter} is +a \grammarterm{parameter-declaration} that declares a pack\iref{dcl.fct}, or +otherwise has an ellipsis prior to its optional \grammarterm{identifier}, +then the \grammarterm{template-parameter} +declares a template parameter pack\iref{temp.variadic}. +A template parameter pack that is a \grammarterm{parameter-declaration} whose type +contains one or more unexpanded packs is a pack expansion. Similarly, +a template parameter pack that is a template template parameter with a +\grammarterm{template-parameter-list} containing one or more unexpanded +packs is a pack expansion. +A type parameter pack with a \grammarterm{type-constraint} that +contains an unexpanded parameter pack is a pack expansion. +A template parameter pack that is a pack +expansion shall not expand a template parameter pack declared in the same +\grammarterm{template-parameter-list}. +\begin{example} +\begin{codeblock} +template // \tcode{Types} is a template type parameter pack + class Tuple; // but not a pack expansion + +template // \tcode{Dims} is a constant template parameter pack + struct multi_array; // but not a pack expansion + +template + struct value_holder { + template struct apply { }; // \tcode{Values} is a constant template parameter pack + }; // and a pack expansion + +template // error: \tcode{Values} expands template type parameter + struct static_array; // pack \tcode{T} within the same template parameter list +\end{codeblock} +\end{example} + \pnum There is no semantic difference between \keyword{class} @@ -277,18 +383,7 @@ \keyword{typename} followed by a \grammarterm{qualified-id} -denotes the type in a non-type -\begin{footnote} -Since template -\grammarterm{template-parameter}{s} -and template -\grammarterm{template-argument}{s} -are treated as types for descriptive purposes, the terms -\term{non-type parameter} -and -\term{non-type argument} -are used to refer to non-type, non-template parameters and arguments. -\end{footnote} +denotes the type in a \grammarterm{parameter-declaration}. A \grammarterm{template-parameter} of the form \keyword{class} \grammarterm{identifier} is a \grammarterm{type-parameter}. @@ -298,56 +393,44 @@ int i; template void f(T t) { - T t1 = i; // template-parameters \tcode{T} and \tcode{i} + T t1 = i; // template parameters \tcode{T} and \tcode{i} ::T t2 = ::i; // global namespace members \tcode{T} and \tcode{i} } \end{codeblock} -Here, the template \tcode{f} has a \grammarterm{type-parameter} -called \tcode{T}, rather than an unnamed non-type -\grammarterm{template-parameter} of class \tcode{T}. +Here, the template \tcode{f} has a type template parameter +called \tcode{T}, rather than an unnamed constant +template parameter of class \tcode{T}. \end{example} -A \grammarterm{template-parameter} declaration shall not -have a \grammarterm{storage-class-specifier}. -Types shall not be defined in a \grammarterm{template-parameter} +The \grammarterm{parameter-declaration} of a \grammarterm{template-parameter} +shall not have a \grammarterm{storage-class-specifier}. +Types shall not be defined in a template parameter declaration. \pnum -The \grammarterm{identifier} in a \grammarterm{type-parameter} is not looked up. -A \grammarterm{type-parameter} -whose \grammarterm{identifier} does not follow an ellipsis -defines its -\grammarterm{identifier} -to be a -\grammarterm{typedef-name} -(if declared without -\keyword{template}) -or -\grammarterm{template-name} -(if declared with -\keyword{template}) +The \grammarterm{identifier} in +a \grammarterm{template-parameter} denoting a type or template +is not looked up. +An \grammarterm{identifier} that does not follow an ellipsis +is defined to be +\begin{itemize} +\item +a \grammarterm{typedef-name} for a \grammarterm{type-parameter}, +\item +a \grammarterm{template-name} for a \grammarterm{variable-tt-parameter}, +\item +a \grammarterm{template-name} for a \grammarterm{type-tt-parameter}, or +\item +a \grammarterm{concept-name} for a \grammarterm{concept-tt-parameter}, +\end{itemize} in the scope of the template declaration. -\begin{note} -A template argument can be a class template or alias template. -For example, - -\begin{codeblock} -template class myarray { @\commentellip@ }; - -template class C = myarray> -class Map { - C key; - C value; -}; -\end{codeblock} -\end{note} \pnum A \grammarterm{type-constraint} \tcode{Q} that designates a concept \tcode{C} can be used to constrain a contextually-determined type or template type parameter pack \tcode{T} with a \grammarterm{constraint-expression} \tcode{E} defined as follows. -If \tcode{Q} is of the form \tcode{C}, -then let \tcode{E$'$} be \tcode{C}. +If \tcode{Q} is of the form \tcode{C}, +then let \tcode{E$'$} be \tcode{C}. Otherwise, let \tcode{E$'$} be \tcode{C}. If \tcode{T} is not a pack, then \tcode{E} is \tcode{E$'$}, @@ -377,7 +460,7 @@ \end{example} \pnum -A non-type \grammarterm{template-parameter} +A constant template parameter shall have one of the following (possibly cv-qualified) types: \begin{itemize} \item a structural type (see below), @@ -401,25 +484,24 @@ \item all base classes and non-static data members are public and non-mutable and \item -the types of all bases classes and non-static data members are -structural types or (possibly multidimensional) array thereof. +the types of all base classes and non-static data members are +structural types or (possibly multidimensional) arrays thereof. \end{itemize} \end{itemize} \pnum An \grammarterm{id-expression} naming -a non-type \grammarterm{template-parameter} of class type \tcode{T} +a constant template parameter of class type \tcode{T} denotes a static storage duration object of type \tcode{const T}, known as a \defn{template parameter object}, -whose value is that of the corresponding template argument +which is template-argument-equivalent\iref{temp.type} to +the corresponding template argument after it has been converted -to the type of the \grammarterm{template-parameter}. -All such template parameters in the program of the same type -with the same value denote the same template parameter object. -A template parameter object shall have constant destruction\iref{expr.const}. +to the type of the template parameter\iref{temp.arg.nontype}. +No two template parameter objects are template-argument-equivalent. \begin{note} If an \grammarterm{id-expression} names -a non-type non-reference \grammarterm{template-parameter}, +a non-reference constant template parameter, then it is a prvalue if it has non-class type. Otherwise, if it is of class type \tcode{T}, it is an lvalue and has type \tcode{const T}\iref{expr.prim.id.unqual}. @@ -429,10 +511,10 @@ using X = int; struct A {}; template void f() { - i++; // error: change of \grammarterm{template-parameter} value + i++; // error: change of template parameter value &x; // OK - &i; // error: address of non-reference template-parameter + &i; // error: address of non-reference template parameter &a; // OK int& ri = i; // error: attempt to bind non-const reference to temporary const int& cri = i; // OK, const reference binds to temporary @@ -443,8 +525,7 @@ \pnum \begin{note} -A non-type -\grammarterm{template-parameter} +A constant template parameter cannot be declared to have type \cv{} \keyword{void}. \begin{example} \begin{codeblock} @@ -455,8 +536,7 @@ \end{note} \pnum -A non-type -\grammarterm{template-parameter} +A constant template parameter \indextext{array!template parameter of type}% of type ``array of \tcode{T}'' or \indextext{function!template parameter of type}% @@ -476,47 +556,34 @@ \end{example} \pnum -A non-type template parameter declared with a type that +A constant template parameter declared with a type that contains a placeholder type with a \grammarterm{type-constraint} introduces the immediately-declared constraint of the \grammarterm{type-constraint} for the invented type corresponding to the placeholder\iref{dcl.fct}. \pnum -A -\defnx{default template-argument}{\idxgram{template-argument}!default} -is a -\grammarterm{template-argument}\iref{temp.arg} specified after -\tcode{=} -in a -\grammarterm{template-parameter}. -A default -\grammarterm{template-argument} -may be specified for any kind of -\grammarterm{template-parameter} -(type, non-type, template) +A \defnadj{default}{template argument} is +a template argument \iref{temp.arg} specified after \tcode{=} +in a \grammarterm{template-parameter}. +A default template argument may be specified for +any kind of template parameter that is not a template parameter pack\iref{temp.variadic}. -A default -\grammarterm{template-argument} -may be specified in a template declaration. -A default -\grammarterm{template-argument} -shall not be specified in the -\grammarterm{template-parameter-list}{s} -of the definition of a member of a class template that appears outside -of the member's class. -A default -\grammarterm{template-argument} +A default template argument may be specified in a template declaration. +A default template argument shall not be specified in +the \grammarterm{template-parameter-list}{s} +of the definition of a member of a class template +that appears outside of the member's class. +A default template argument shall not be specified in a friend class template declaration. If a friend function template declaration $D$ -specifies a default \grammarterm{template-argument}, +specifies a default template argument, that declaration shall be a definition and there shall be no other declaration of the function template which is reachable from $D$ or from which $D$ is reachable. \pnum -The set of default -\grammarterm{template-argument}{s} +The set of default template arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are\iref{dcl.fct.default}. @@ -532,29 +599,25 @@ \end{example} \pnum -If a -\grammarterm{template-parameter} -of a class template, variable template, or alias template has a default -\grammarterm{template-argument}, -each subsequent -\grammarterm{template-parameter} -shall either have a default -\grammarterm{template-argument} -supplied -or be a template parameter pack. If a \grammarterm{template-parameter} -of a primary class template, primary variable template, or alias template -is a template parameter pack, it shall be the last -\grammarterm{template-parameter}. -A template parameter pack of a function template shall not be followed by -another -template parameter unless that template parameter can be deduced from the -parameter-type-list\iref{dcl.fct} of the function template or has a -default argument\iref{temp.deduct}. +If a \grammarterm{template-parameter} +of a class template, variable template, or alias template has +a default template argument, +each subsequent \grammarterm{template-parameter} +shall either have a default template argument supplied or +declare a template parameter pack. +If a \grammarterm{template-parameter} of +a primary class template, primary variable template, or alias template +declares a template parameter pack, +it shall be the last \grammarterm{template-parameter}. +If a \grammarterm{template-parameter} of a function template +declares a template parameter pack, it +shall not be followed by another \grammarterm{template-parameter} +unless that template parameter is deducible from the +parameter-type-list\iref{dcl.fct} of the function template or +has a default argument\iref{temp.deduct}. A template parameter of a deduction guide template\iref{temp.deduct.guide} -that does not have a default argument -shall be deducible -from the parameter-type-list -of the deduction guide template. +that does not have a default argument shall be deducible +from the parameter-type-list of the deduction guide template. \begin{example} \begin{codeblock} template class B; // error @@ -567,15 +630,10 @@ \indextext{\idxcode{<}!template and}% \pnum -When parsing a -default -\grammarterm{template-argument} -for a non-type -\grammarterm{template-parameter}, -the first non-nested -\tcode{>} -is taken as the end of the -\grammarterm{template-parameter-list} +When parsing a default template argument +for a constant template parameter, +the first non-nested \tcode{>} is taken as +the end of the \grammarterm{template-parameter-list} rather than a greater-than operator. \begin{example} \begin{codeblock} @@ -588,16 +646,12 @@ \end{example} \pnum -A -\grammarterm{template-parameter} -of a template -\grammarterm{template-parameter} -is permitted to have a default -\grammarterm{template-argument}. -When such default arguments are specified, they apply to the template -\grammarterm{template-parameter} -in the scope of the template -\grammarterm{template-parameter}. +A \grammarterm{template-parameter} of +a template \grammarterm{template-parameter} +is permitted to have a default template argument. +When such default arguments are specified, +they apply to the template \grammarterm{template-parameter} +in the scope of the template \grammarterm{template-parameter}. \begin{example} \begin{codeblock} template