diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 2c1415675c..4135d1d0f2 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -12,7 +12,7 @@ defaults: jobs: run-checks: name: Run checks - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: checkout diff --git a/papers/n4918.html b/papers/n4918.html new file mode 100644 index 0000000000..a21471cc39 --- /dev/null +++ b/papers/n4918.html @@ -0,0 +1,2007 @@ + + + + + +N4918 + + +

N4918 Editors’ Report:
Programming Languages — C++

+ +

Date: 2022-09-06

+ +

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 most of the draft +motion applications, and to Hewill Kang for spotting and sending corrections for +many editorial issues.

+ +

New papers

+ + + +

Motions incorporated into working draft

+ +

Core working group polls

+ +

CWG poll 1: Accept as Defect Reports all issues except 2507 and 2586 in +P2622R0 +(Core Language Working Group "ready" Issues for the July, 2022 meeting) and +apply their proposed resolutions to the C++ Working Paper.

+ +

CWG poll 2: Apply the proposed resolution of issues 2507 and 2586 in +P2622R0 +(Core Language Working Group "ready" Issues for the July, 2022 meeting) to the +C++ Working Paper.

+ +

CWG poll 3: Accept as a Defect Report and apply the changes in +P2468R2 +(The Equality Operator You Are Looking For) to the C++ Working Paper.

+ +

CWG poll 4: Accept as a Defect Report and apply the changes in +P2327R1 +(De-deprecating volatile compound operations) to the C++ Working Paper.

+ +

CWG poll 5: Apply the changes in +P2437R1 +(Support for #warning) to the C++ Working Paper.

+ +

CWG poll 6: Apply the changes in +P2362R3 +(Remove non-encodable wide character literals and multicharacter wide character +literals) to the C++ Working Paper.

+ +

CWG poll 7: Apply the changes in +P2324R2 +(Labels at the end of compound statements (C compatibility)) to the C++ Working +Paper.

+ +

CWG poll 8: Apply the changes in +P2290R3 +(Delimited escape sequences) to the C++ Working Paper.

+ +

CWG poll 9: Apply the changes in +P2448R2 +(Relaxing some constexpr restrictions) to the C++ Working Paper.

+ +

CWG poll 10: Apply the changes in +P2266R3 +(Simpler implicit move) to the C++ Working Paper.

+ +

CWG poll 11: Apply the changes in +P2071R2 +(Named universal character escapes) to the C++ Working Paper.

+ +

CWG poll 12: Apply the changes in +P1169R4 +(static operator()) to the C++ Working Paper.

+ +

CWG poll 13: Accept as a Defect Report and apply the changes in +P2280R4 +(Using unknown pointers and references in constant expressions) to the C++ +Working Paper.

+ +

CWG poll 14: Apply the changes in +P1467R9 +(Extended floating-point types and standard names) to the C++ Working Paper.

+ +

CWG poll 15: Accept as a Defect Report +P2493R0 +(Missing feature test macros for C++20 core papers). (The paper was already +adopted at the February, 2022 meeting, and no changes to the Working Paper +result from it now.)

+ +

CWG poll 16: Apply the changes in +P2582R1 +(Wording for class template argument deduction from inherited constructors) to +the C++ Working Paper.

+ +

CWG poll 17: Apply the changes in +P1774R8 +(Portable assumptions) to the C++ Working Paper.

+ +

CWG poll 18: Apply the changes in +P2295R6 +(Support for UTF-8 as a portable source file encoding) to the C++ Working Paper.

+ +

CWG poll 19: Accept as a Defect Report and apply the changes in +P2513R3 +(char8_t Compatibility and Portability Fix) to the C++ Working Paper.

+ +

CWG poll 20: Accept as a Defect Report and apply the changes in +P2460R2 +(Relax requirements on wchar_t to match existing practices) to the C++ Working +Paper.

+ +

CWG poll 21: Accept as a Defect Report and apply the changes in +P2579R0 +(Mitigation strategies for P2036 "Changing scope for lambda +trailing-return-type") to the C++ Working Paper.

+ +

Library working group polls

+ +

LWG poll 1: Apply the changes for all Ready issues in +P2618R0 (C++ +Standard Library Issues to be moved in Virtual Plenary, Jul. 2022) to the C++ +working paper.

+ +

LWG poll 2: Apply the changes in +P0009R18 +(MDSPAN) to the C++ working paper.

+ +

LWG poll 3: Apply the changes in +P2599R2 +(index_type & size_type in mdspan) to the C++ working paper.

+ +

LWG poll 4: Apply the changes in +P2604R0 +(mdspan: rename pointer and contiguous) to the C++ working paper.

+ +

LWG poll 5: Apply the changes in +P2613R1 (Add +the missing empty to mdspan) to the C++ working paper.

+ +

LWG poll 6: Apply the changes in +P0429R9 (A +Standard flat_map) to the C++ working paper.

+ +

LWG poll 7: Apply the changes in +P1222R4 (A +Standard flat_set) to the C++ working paper.

+ +

LWG poll 8: Apply the changes in +P1223R5 +(find_last) to the C++ working paper.

+ +

LWG poll 9: Apply the changes in +P1642R11 +(Freestanding Library: Easy [utilities], [ranges], and [iterators]) to the C++ +working paper.

+ +

LWG poll 10: Apply the changes in +P1899R3 +(stride_view) to the C++ working paper.

+ +

LWG poll 11: Apply the changes in +P2093R14 +(Formatted output) to the C++ working paper.

+ +

LWG poll 12: Apply the changes in +P2165R4 +(Compatibility between tuple, pair and tuple-like objects) to the C++ +working paper.

+ +

LWG poll 13: Apply the changes in +P2278R4 +(cbegin should always return a constant iterator) to the C++ working paper.

+ +

LWG poll 14: Apply the changes in +P2286R8 +(Formatting Ranges) to the C++ working paper.

+ +

LWG poll 15: Apply the changes in +P2291R3 (Add +Constexpr Modifiers to Functions to_chars and from_chars for Integral Types +in <charconv> Header) to the C++ working paper.

+ +

LWG poll 16: Apply the changes in +P2302R4 +(std::ranges::contains) to the C++ working paper.

+ +

LWG poll 17: Apply the changes in +P2322R6 +(ranges::fold) to the C++ working paper.

+ +

LWG poll 18: Apply the changes in +P2374R4 +(views::cartesian_product) to the C++ working paper.

+ +

LWG poll 19: Apply the changes in +P2540R1 +(Empty Product for certain Views) to the C++ working paper.

+ +

LWG poll 20: Apply the changes in +P2404R3 +(Move-only types for equality_comparable_with, totally_ordered_with, and +three_way_comparable_with) to the C++ working paper.

+ +

LWG poll 21: Apply the changes in +P2408R5 +(Ranges iterators as inputs to non-Ranges algorithms) to the C++ working paper.

+ +

LWG poll 22: Apply the changes in +P2417R2 (A +more constexpr bitset) to the C++ working paper.

+ +

LWG poll 23: Apply the changes in +P2419R2 +(Clarify handling of encodings in localized formatting of chrono types) to the +C++ working paper.

+ +

LWG poll 24: Apply the changes in +P2438R2 +(std::string::substr() &&) to the C++ working paper.

+ +

LWG poll 25: Apply the changes in +P2446R2 +(views::as_rvalue) to the C++ working paper.

+ +

LWG poll 26: Apply the changes in +P2465R3 +(Standard Library Modules std and std.compat) to the C++ working paper.

+ +

LWG poll 27: Apply the changes in +P2445R1 +(std::forward_like) to the C++ working paper.

+ +

LWG poll 28: Apply the changes in +P2467R1 +(Support exclusive mode for fstreams) to the C++ working paper.

+ +

LWG poll 29: Apply the changes in +P2474R2 +(views::repeat) to the C++ working paper.

+ +

LWG poll 30: Apply the changes in +P2494R2 +(Relaxing range adaptors to allow for move only types) to the C++ working paper.

+ +

LWG poll 31: Apply the changes in +P2499R0 +(string_view range constructor should be explicit) to the C++ working paper.

+ +

LWG poll 32: Apply the changes in +P2502R2 +(std::generator: Synchronous Coroutine Generator for Ranges) to the C++ working +paper.

+ +

LWG poll 33: Apply the changes in +P2508R1 +(Exposing std::basic-format-string<charT, Args...>) +to the C++ working paper.

+ +

LWG poll 34: Apply the changes in +P2517R1 (Add +a conditional noexcept specification to std::apply) to the C++ working paper.

+ +

LWG poll 35: Apply the changes in +P2520R0 +(move_iterator<T*> should be a random access iterator) to the C++ working +paper.

+ +

LWG poll 36: Apply the changes in +P2549R1 +(std::unexpected<E> should have error() as member accessor) to the C++ +working paper.

+ +

LWG poll 37: Apply the changes in +P2585R1 +(Improving default container formatting) to the C++ working paper.

+ +

LWG poll 38: Apply the changes in +P2590R2 +(Explicit lifetime management) to the C++ working paper.

+ +

Editorial changes

+ +

Notes on motions

+ + + +

Noteworthy editorial changes

+ + + +

Minor editorial changes

+ +

A log of editorial fixes made to the working draft since N4910 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 fb8135e5ec22acd26cb0dcb1bface21eee118895
+Author: hewillk <67143766+hewillk@users.noreply.github.com>
+Date:   Sun Mar 6 20:22:18 2022 +0800
+
+    [range.utility.conv.general] Add missing template parameter to container-inserter
+
+commit b7c1f9a77eac8dfeb4cb2e92bd3b2a57d05c298a
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Mar 25 09:37:42 2022 +0100
+
+    [spanbuf] Fix template name in subclause heading (#5365)
+
+commit cdca862605ae315e2d7a1ca7c7c1b011651944d2
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Mar 25 10:44:58 2022 +0100
+
+    [span.streams] Move non-member swaps to header synopsis (#5366)
+
+commit 478b8f8807e5b4561874842aa24a132558682f00
+Author: A. Jiang <de34@live.cn>
+Date:   Thu Mar 31 19:34:03 2022 +0800
+
+    [alg.min.max] Consistently specify ranges::minmax_element with minmax_element_result (#5376)
+
+    LWG3180 was incompletely applied with commit e33be08f8ca49a9a139aa81b7a1ba9787d85f4fc.
+
+commit c92196bc67e252f06907c6de44173ce7157d71df
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Apr 1 13:38:03 2022 +0200
+
+    [memory.syn] Add missing closing bracket for attribute
+
+commit 1d2d223ab9fee202b67b31b32b85f44e3f9dc187
+Author: hewillk <67143766+hewillk@users.noreply.github.com>
+Date:   Thu Mar 24 02:13:51 2022 +0800
+
+    [range.adjacent.transform.iterator] Fix wrong template parameter in adjacent_transform_view::iterator
+
+commit 4813f202b3e2f6d0062967b9fd96ca54b91c7b65
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed Mar 30 08:29:55 2022 +0200
+
+    [stacktrace.syn] Add '#include <compare>'
+
+    LWG3330 added #include <compare> to all header files
+    where a three-way comparison operator was declared,
+    but missed this one.
+
+commit d9040a775aa528f0576453532f3cb5058a6e6f24
+Author: A. Jiang <de34@live.cn>
+Date:   Wed Apr 6 20:03:39 2022 +0800
+
+    [allocator.requirements.general] Specify all member types with typename (#5386)
+
+commit 2bfa7c4cc96203e03763816cf310e54e5b8940bb
+Author: Daniel Krügler <daniel.kruegler@gmail.com>
+Date:   Fri Apr 15 21:26:27 2022 +0200
+
+    [temp.constr.normal] Add missing semicolon in example (#5395)
+
+commit a8dbfc63227bf596dcf72a31c9fef4af8af9e592
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed Apr 20 14:41:22 2022 +0100
+
+    [depr.tuple,depr.variant] Use struct class-key consistently (#5402)
+
+commit 4fc805d949bfc99ee6cfcf666123eb982fc4c465
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Apr 21 09:27:57 2022 +0200
+
+    [expr.prim.lambda.general] Clarify deduced lambda return type
+
+commit 5fb0fd092782f57e8395841470c92176412a10a3
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Thu Mar 24 09:29:07 2022 +0000
+
+    [expected.un.object.general] Reorder constructors in synopsis
+
+    This matches the order in [expected.un.ctor].
+
+commit 8e7a9b9fbf2f7a7dfa913a77068b6a6d3488e521
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Thu Mar 24 09:36:55 2022 +0000
+
+    [expected.un.object] Remove unnecessary subclause nesting
+
+    All the other class templates in <expected> are at the rSec3 level, but
+    std::unexpected is below a mostly useless rSec3 [expected.unexpected].
+    This subclause has two children, [expected.un.general] which is a single
+    sentence, and [expected.un.object] which defines the class template and
+    its members. If we merge the single sentence from [expected.un.general]
+    into the same subclause as the class synopsis then we can get remove the
+    unnecessary nesting. As a nice side effect, this also gets rid of
+    "object" in the [expected.un.object] stable name, which doesn't really
+    make sense in context.
+
+commit 3372ed0572fd8aa59ed9e59432cd8f593868be49
+Author: Casey Carter <Casey@Carter.net>
+Date:   Mon Apr 25 13:24:24 2022 -0700
+
+    [range.utility.conv.general] Strike extraneous semicolon (#5414)
+
+commit 4b7deb009c4dfbbe8f2c879f764be446f94957b2
+Author: xmh0511 <970252187@qq.com>
+Date:   Tue Apr 26 04:26:19 2022 +0800
+
+    [lex.ccon] Fix typo in character name for U+0027 (#5412)
+
+commit 93de6031da2ef99b402e18ee8941fd6c7b554ce4
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Apr 26 14:14:02 2022 +0200
+
+    [string.view.deduct] Move to immediately after [string.view.cons] (#5397)
+
+commit 41bc0c2ab38c32638685ef9a5068e06abbfc07f3
+Author: hewillk <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Apr 26 20:16:26 2022 +0800
+
+    [expected] Add missing noexcept for expected::error() (#5381)
+
+commit b075835f134e4956fe27eaa5323655137aff3d45
+Author: Hui <65944694+huixie90@users.noreply.github.com>
+Date:   Tue Apr 26 18:56:30 2022 +0100
+
+    [iterator.concept.readable] Remove obsolete note (#5408)
+
+    The note was obsoleted by P1878R1.
+
+commit eed51157b2011478eb40254fbf191f2dd5fca7ca
+Author: hewillk <67143766+hewillk@users.noreply.github.com>
+Date:   Tue May 3 15:26:39 2022 +0800
+
+    [expected.object.general] Remove explicit keyword for copy/move constructors (#5380)
+
+commit d23b318949c0a74c6f93f50afb1375ba9eb7aefd
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed May 4 00:50:55 2022 +0100
+
+    [stringbuf.virtuals] add "override" to setbuf
+
+commit fbe06e9076db0116e395e969f4cb921e45ae964a
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed May 4 00:51:45 2022 +0100
+
+    [adjacent.difference] fix grammar typo
+
+commit bb8729f3cba593b963031bb25a1a4f12e12ad4fb
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed May 4 00:52:40 2022 +0100
+
+    [streambuf.virt.get] fix grammar typo
+
+commit 6fa045bf939eeff4dcea56e1a84ab7e1aac69f78
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Wed May 4 01:12:12 2022 +0100
+
+    [thread.lock.unique.cons] Use nullptr for null pointer constant
+
+commit f6791f7f9346c007921fec0b406a9edcbf667951
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 4 11:55:03 2022 +0200
+
+    [syncstream.osyncstream.cons] Fix use of parameter name (#5445)
+
+commit 74ad79739e2a13022bc6a33ff2e32efe59a47578
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 4 11:55:45 2022 +0200
+
+    [thread.sema.cnt] Add missing parentheses on function call expression (#5443)
+
+commit 8147026d04fe8fb44ed439cea950b5dab136c04c
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 4 11:56:14 2022 +0200
+
+    [cons.slice] Add copy constructor for 'slice' to synopsis (#5444)
+
+commit fb379c19180d1e26b2b8146d547bcc84c59a0da5
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed May 4 11:56:50 2022 +0200
+
+    [over.match.best.general] Fix typo in example (#5446)
+
+commit 81e506da21960bc70c271f775673a311ec957f6b
+Author: Casey Carter <Casey@Carter.net>
+Date:   Wed May 4 02:59:27 2022 -0700
+
+    [ranges.syn] remove trailing `-> see below` return type from three `to` overloads (#5419)
+
+    Since there is actually no return type specification to see below in [range.utility.conv].
+
+commit 11d886b5c6062ec7291469514eb07424811e4f65
+Author: languagelawyer <38548419+languagelawyer@users.noreply.github.com>
+Date:   Tue Apr 26 17:39:39 2022 +0300
+
+    [class.access] Remove dangling Note
+
+    Invalidated by P1847R4
+
+commit 5032e88247bafb5c44dcd4d8ac2ffe3f8bff1bd9
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Apr 23 22:15:46 2022 +0200
+
+    [associative] Add "i.e." in front of explanation
+
+commit 445d18255713e183df2819e565aa5faa7f85bb1d
+Author: hewillk <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Apr 1 22:46:44 2022 +0800
+
+    [range.utility.conv.general] Add missing constexpr for container-inserter
+
+commit 64969e2057ef55b7ac3db8e23c37547edff5c8cf
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 13:14:25 2022 +0200
+
+    [intro.memory] Fix missing semicolon in example
+
+commit dcf0f144f72e8116c59c188c5057a6ca8a7615d3
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 13:35:33 2022 +0200
+
+    [intro.progress] Fix grammar typo
+
+commit 8c743eacc4b8609650d690b774f855507bd0846f
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 13:41:54 2022 +0200
+
+    [expr.prim.lambda.general] Fix missing capture-default in example
+
+commit 359b8f41027c970bbbc63f1319a890adaa338f6f
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 16:59:35 2022 +0200
+
+    [expr.await] Fix English grammar in string-literal in example
+
+commit 117b352d584cac601c22c63328355658271a6f17
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:05:50 2022 +0200
+
+    [expr.xor] Fix grammar typo
+
+commit 980aded4060cb408c053b0ee4620a71f3b6b73c6
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:06:01 2022 +0200
+
+    [expr.or] Fix grammar typo
+
+commit edb43d00ec4f5e98d45c03408b5d0be6b0484c27
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:09:06 2022 +0200
+
+    [expr.yield] Fix typos in examples
+
+commit 451d8b95bd4c04bf89a5915eb973f837873c432b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:20:11 2022 +0200
+
+    [dcl.fct.default] Fix grammar typo in comment in example
+
+commit cd2690e9ace12f901acce1c1e9157f5cbbf06b24
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:21:32 2022 +0200
+
+    [dcl.init.aggr] Fix grammar typo in example
+
+commit cbc1a36376f32e9d31d5276ba44d8237d0632c37
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:24:29 2022 +0200
+
+    [dcl.fct.def.coroutine] Fix grammar typo
+
+commit d7be2ebee9dd3df849cf87bed768f9bb9f8684f8
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:27:11 2022 +0200
+
+    [class.copy.ctor] Fix grammar typo
+
+commit 4284e8c31673912ae92bc210bb39aa4b05f0ed86
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:31:25 2022 +0200
+
+    [class.expl.init] Fix grammar typo
+
+commit 6c0d1411779d9e2c3e9a59d10b09605b6e5f1482
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 17:35:00 2022 +0200
+
+    [class.base.init] Fix grammar typo in note
+
+commit 40483ba8cff2165cd81dd75718559037af3ecaa8
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 22:43:03 2022 +0200
+
+    [over.match.class.deduct] Fix syntax error in example
+
+commit 04cb8da6485b09592008c82eb330125fbf1034cd
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu May 5 23:15:42 2022 +0200
+
+    [temp.decls.general] Fix missing comma
+
+commit e6633adbb2f3a6590cd75a000b377c8736c65094
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri May 6 00:17:50 2022 +0200
+
+    [temp.deduct.type] Fix grammar typo
+
+commit 1386c5b2cf41b713a12f526077eb578b68bacb9b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri May 6 00:19:23 2022 +0200
+
+    [temp.over] Fix grammar typos
+
+commit 21dc6d863a5acb0c3e5ec008bddb1c02b3dcd29a
+Author: hewillk <67143766+hewillk@users.noreply.github.com>
+Date:   Thu May 19 11:23:47 2022 +0800
+
+    [range.join.view] Simplify range_reference_t<V> to InnerRng
+
+    I think this is a reasonable simplification and also makes it consistent with join_with_view.
+
+commit 2101d81b42bfcb7ab2227617a5ebe86e0b5733e8
+Author: Casey Carter <Casey@Carter.net>
+Date:   Mon May 23 04:39:15 2022 -0700
+
+    [expected.object.ctor] Use the injected-class-name to refer to the current instantiation (#5485)
+
+    ... as is conventional in library wording.
+
+commit 31be778d39b144fe867e24d80481786ad012661e
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sun May 29 04:51:06 2022 +0800
+
+    [ranges] Remove redundant "exposition only" comments in \itemdecl (#5499)
+
+commit aff22aca63d0fb4b183cf073de8abfd4b9bb22bd
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Jun 10 00:24:11 2022 +0800
+
+    [range.istream.view] Add reference for basic_istream_view::iterator (#5514)
+
+commit 10a20b22491f1ff39a47847a68c9e4a648754d10
+Author: Mathias Stearn <redbeard0531@gmail.com>
+Date:   Thu Jun 9 18:52:42 2022 +0200
+
+    [res.on.functions] Use regular "behavior is undefined" words of power (#5513)
+
+commit 4bfa5ddf04586b6df76e0f44e4cde8b59f4a0401
+Author: Casey Carter <Casey@Carter.net>
+Date:   Thu Jun 9 09:56:29 2022 -0700
+
+    [range.istream.iterator] basic_istream_view::iterator is not a class template (#5515)
+
+commit f73087971183d1daa992ad5165946609a77d39ff
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 12 16:18:19 2022 +0200
+
+    [func.wrap.move.ctor] Fix typo naming template parameter packs (#5517)
+
+commit 8d3f43888013437a2870877f00f017860b083df4
+Author: Johel Ernesto Guerrero Peña <johelegp@gmail.com>
+Date:   Sat Jun 11 17:34:09 2022 -0400
+
+    [range.adjacent.iterator] Use correct descriptive element
+
+commit d86e1ef9ef8514e570fdbbc5038f71e272dbb008
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sun Jun 12 03:11:07 2022 +0800
+
+    [ranges.syn] Fix the constraints order of slide_view
+
+commit c4a46fb7343c591f8844c2615ec25cfe8021656a
+Author: hewillk <67143766+hewillk@users.noreply.github.com>
+Date:   Sat May 21 20:39:59 2022 +0800
+
+    [move.iter.cons] Add missing Returns
+
+commit 45498df90fa8fa6ffb4de7341c65a2924de9879c
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Thu Jun 16 04:57:27 2022 +0800
+
+    [range.join.with.sentinel] Add missing curly brace (#5530)
+
+commit d78d53f96d076f66a8af4ca7e71ae48e1d0596be
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 16 13:52:29 2022 +0200
+
+    [allocator.adaptor.syn] Fix typo in comment in header synopsis
+
+commit 01f16bc99a6a89e69b7a6ec5ae8bfe307ec5299a
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 16 17:33:52 2022 +0200
+
+    [functional.syn,func.search.default] Fix name of template parameter
+
+commit 0678f9986b2c1f75e55d596f63876979433522d4
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 16 17:43:07 2022 +0200
+
+    [meta.rel] Add parentheses for consistency
+
+    Parentheses are used for is_pointer_interconvertible_base_of.
+
+commit c8a496c62d973305cd6eb5a23d80f169062335fc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 16 17:51:57 2022 +0200
+
+    [string.view.general] Add missing template-argument-list
+
+commit 70d07925ad874144f2dae4359f5a17c6cada1cdb
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 16 17:55:30 2022 +0200
+
+    [forward.list.modifiers] Fix misspelled parameter name
+
+commit 66fd28de5c730a271bcf631f8452048c0e709232
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 16 17:56:48 2022 +0200
+
+    [set.cons] Fix grammar typo
+
+commit de6b0e70ffe2da0a0f91ce434863202f78c9e029
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 16 18:00:21 2022 +0200
+
+    [unord.map.overview] Fix presentation of member types
+
+commit 5be153e248d9e741c841ff3ab6c2e3714ecba24b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:14:19 2022 +0200
+
+    [unord.set.overview] Fix presentation of member types
+
+commit 633178f3fd48a784a96a6610f6b12c10700603c0
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:15:22 2022 +0200
+
+    [unord.multiset.overview] Fix presentation of member types
+
+commit 5ae534c0c522cf661d3e94c58f54c7d37cf7905a
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:18:34 2022 +0200
+
+    [random.access.iterators] Add semicolon at end of statement
+
+commit f60caf420b5210f0ad284999a1e471d50c424856
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:21:11 2022 +0200
+
+    [range.req.general] Fix grammar typo
+
+commit 75436ee3dd005cf13153ee05c9174a3a3df0054d
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:32:31 2022 +0200
+
+    [range.take.view] Replace 'struct' with 'class' for consistency
+
+commit 8738cac27de2d66addf735f4fc2b370b73bb9ecc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:33:59 2022 +0200
+
+    [range.take.while.overview] Highlight use of ranges::begin
+
+commit 51cad172464c89cc14fff19d87d6bba6bc68f61d
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:38:54 2022 +0200
+
+    [algorithms.requirements] Add commas for readability
+
+commit 5096e87c6c882ae2aff40c3558db7c2ec95ff4a8
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:39:08 2022 +0200
+
+    [algorithms.requirements] Add hyphen for non-copied
+
+commit 63f3e4030497e43f39ff89ec0171f89a11dfc0a7
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 17 08:41:53 2022 +0200
+
+    [alg.equal] Add missing period
+
+commit 736c755c70be70d5fb75e71f2c212c3c633ddc34
+Author: Casey Carter <Casey@Carter.net>
+Date:   Thu Jun 23 14:26:40 2022 -0700
+
+    [priqueue.overview] Add misssing `>` to deduction guide (#5535)
+
+commit 3bf6ac52ddd619ae925d32ebb68a90a5bec0c115
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 24 15:50:30 2022 +0200
+
+    [class.prop] Clarify definition of implicit-lifetime class (#5319)
+
+commit 314fa9e2c16bcdaba33febddf2992b3e26c02212
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Wed Jul 13 01:54:20 2022 +0800
+
+    [sequence.reqmts] Add ranges namespace qualifier for range concepts (#5563)
+
+commit 433b7af41ef02b8656c3153ab6ebb1c1c616f5b3
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Wed Jul 13 23:40:21 2022 +0800
+
+    [range.take.overview] Fix punctuation (#5564)
+
+commit f6cb84439e8094ec7c67c708d1cc0ddef59262ec
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Jul 26 23:09:38 2022 +0800
+
+    [ranges.syn] Add \ref for `ref_view` (#5652)
+
+commit c816ae797e36daa466c287f3eff445aa87d8bfeb
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Jul 29 03:11:43 2022 +0800
+
+    [istreambuf.iterator.general] Add \ref for proxy (#5669)
+
+commit d59a4f3392fd1cf87af4ba128518fb4c00cbf77c
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Jul 29 03:13:33 2022 +0800
+
+    [algorithm.syn,bitset.syn,rand.synopsis,valarray.syn] Add \ref for header (#5666)
+
+commit 78b91e849b270423ec3296f7f95666078531e032
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sat Jul 30 05:13:40 2022 +0800
+
+    [range.join.with.overview,range.split.overview] use qualified name in examples (#5683)
+
+commit e24445344d26e3d9a3ad92b939b8c034daa47eb4
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Aug 14 20:53:03 2022 +0100
+
+    [mdspan.*] Replace remaining "pointer"s with "data_handle_type".
+
+    These edits are part of LWG Motion 4 (P2604R0) but were accidentally omitted.
+
+commit 762480c9317759ffd6db76f7fef27744776e081d
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Aug 17 11:41:51 2022 +0100
+
+    [ranges] Remove now-unused exposition-only "tuple-or-pair".
+
+    Also fix one missed replacement of "tuple-or-pair" with "tuple" as
+    instructed by LWG-Motion 12 (P2165R4, "tuple-like objects").
+
+commit b832e2702df41ebe79ddd9d159ac71e68e9b772a
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Aug 14 22:26:15 2022 +0100
+
+    [container.reqmnts] Remove stray `{}`
+
+commit f09e7c5164d6dbc43e4a160aa4676725a83f488d
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Aug 17 15:03:41 2022 +0100
+
+    [expr.spaceship, fs.path.generic, temp.inst] Use em-dash for parentheticals, not en-dash.
+
+    We are using em-dashes elsewhere already.
+
+commit 5dd17bf20e46a2964131ec208b6ed31cc659c400
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Wed Aug 17 23:18:35 2022 +0100
+
+    [ranges] Add missing requirement on itemdecl, and fix spacing
+
+commit bb1145f751e2de491873aac5a42faf0a6931c218
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Aug 12 12:03:55 2022 +0100
+
+    [mdspan.{overview,extents.ctor}] Increase reuse of definitions
+
+commit e97f917d3fd39d7fb2421105d8e45cb73bd24a1e
+Author: Eelis van der Weegen <eelis@eelis.net>
+Date:   Thu Aug 18 18:42:15 2022 +0200
+
+    [range.zip.transform.view] Fix typo: mmove_constructible.
+
+commit f440cfa4e3ebf139b5acec3735e90d4acf5785e6
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Aug 18 15:25:55 2022 +0100
+
+    [ranges.syn] Add missing "freestanding" comment for as_rvalue.
+
+commit 999005ab72ca0078b3361979584007dd9d991fac
+Author: Yihe Li <winmikedows@hotmail.com>
+Date:   Fri Aug 5 08:49:10 2022 +0800
+
+    [strings.general] Add <string> header to "String classes" row
+
+commit 1fbf5f8b683802849cfc8bb57fef3f48a61bd242
+Author: Yihe Li <winmikedows@hotmail.com>
+Date:   Fri Aug 5 08:49:40 2022 +0800
+
+    [thread.general] Remove non-existent header
+
+commit 0d7d1d70641a773f67b08f4de44e53f00e3b352d
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 24 15:40:43 2022 +0200
+
+    [temp.inst] Clarify referent of 'declaration'
+
+commit 99bc532e3c9440defd761985d2329da064b7f9f9
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jun 23 23:17:13 2022 +0200
+
+    [module.private.frag] Remove misleading example and broaden note
+
+commit 596137c054407d4d5f2ccf327bd5d3e2a8b4fef5
+Author: A. Jiang <de34@live.cn>
+Date:   Tue May 17 09:49:27 2022 +0800
+
+    [mem.poly.allocator.class.general] Clarify polymorphic_allocator<void> etc.
+
+commit 193cfc17cbb73e7e6c65d1e596ef9c1a035c7811
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Nov 5 19:58:41 2021 +0100
+
+    [diff.dcl] Discuss 'alignas' placement restrictions
+
+commit 8b2d70502c379b96ddb9d6eb97d5aafcc1d4765c
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Nov 5 20:00:00 2021 +0100
+
+    [diff.dcl] Remove 'implicit int' discussion
+
+    C99 has removed implicit int.
+
+commit f91c425a8fe6f0dd826bd399a5bc82796aec8180
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Mar 4 21:20:21 2022 +0100
+
+    [diff.expr] Remove 'implicit function declaration' discussion
+
+    C99 has removed implicit function declarations.
+
+commit b208eb4da5a97cf800f2822318fd487f332d82ad
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 06:22:04 2019 +0000
+
+    [meta.trans.other] Use "denotes" in decay, enable_if and conditional
+
+commit 769e15bd0559a8ff572d2c508f2cce0227229a39
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 07:04:02 2019 +0000
+
+    [meta.unary.prop.query] Use "is an array type" not "names an array type"
+
+commit 3d010460fc4159b6f99d430a3cf0eb0ff30d0053
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 07:05:09 2019 +0000
+
+    [meta.trans.ref] Use "is a referenceable type" and "denotes the type"
+
+commit 66cb97967adb501ff352b6e69815b4db10e095bf
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 07:06:14 2019 +0000
+
+    [meta.trans.sign] Use "is a ... type" and "denotes the type"
+
+commit 485192fb3872c1da42d6cc0ff89230ecb7760c9c
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 07:06:46 2019 +0000
+
+    [meta.trans.arr] Use "is a type" not "names a type"
+
+    Also use "denotes" instead of "names" for member typedefs.
+
+commit e2d032255ad0f346144659ba43d3eb184163c8bb
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 07:07:15 2019 +0000
+
+    [meta.trans.ptr] Use "is a referenceable type" not "names ..."
+
+commit 2c9482a15375291528e8742dc7972450c9597d96
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 07:09:00 2019 +0000
+
+    [meta.trans.other] Use "denotes"
+
+commit c51087e82583b589481f03d4dad2190a569ce857
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Feb 22 07:16:14 2019 +0000
+
+    [meta.trans.cv] use "denotes" in specification of member typedefs
+
+commit 935ec9e8f13d41bc09f8a27a917008ddf2724a29
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Tue Apr 23 10:33:16 2019 +0100
+
+    [refwrap.unwrapref] Use "denotes" for member typedef
+
+commit e412ba9b687e4cdd8ed7546b3ec44122b6baabc5
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Fri Apr 22 18:20:59 2022 +0100
+
+    [depr.meta.types] use "denotes" for member typedefs
+
+commit 887c0330bdd2e4b504854a5c9d34621e5d10a3d2
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Nov 27 21:27:28 2018 +0100
+
+    [cmp.categories] Replace 'operator admits' phrasing.
+
+commit 1e3e4180ee26e06abe6eeb648537b36baa92c5b7
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Aug 19 01:33:25 2022 +0800
+
+    [range.as.const.view] Add missing angle bracket (#5745)
+
+commit d732538953bab8ccdbe4388cfb39b8542a01dc65
+Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
+Date:   Thu Jul 21 10:09:09 2022 -0400
+
+    [map.cons,multimap.cons,multiset.cons,set.cons,associative.reqmts.general] "sorted with respect to `comp`"
+
+    https://cplusplus.github.io/LWG/issue3713
+    LWG3713 points out that we temporarily lost the term of art
+    "sorted with respect to `comp`," and brings back a definition
+    for it. However, several places in the existing draft never
+    actually used that term of art in the first place. Fix them
+    up so that they do.
+
+commit 4db1d62426ef9a9cd8689585d43da38dd3731696
+Author: A. Jiang <de34@live.cn>
+Date:   Fri Aug 19 01:36:40 2022 +0800
+
+    [allocator.requirements.general] Use newer style for SimpleAllocator
+
+commit a458849089b29e3dfc5f9736799c1c6403223f8f
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 12 16:11:08 2022 +0200
+
+    [thread.lock.unique.locking] Fix function call expressions
+
+commit dd4ecf3d19bf8a04899324fc72c690880a328a64
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri May 13 21:51:13 2022 +0200
+
+    [stacktrace.basic.nonmem] Add missing \pnum before \recommended
+
+    Also augment check script
+
+commit fe24762404f5ac7bbd6f139a44dbfa42663ec796
+Author: Barry Revzin <barry.revzin@gmail.com>
+Date:   Thu Aug 18 16:03:10 2022 -0500
+
+    [stmt.pre] List "compound-statement" explicitly as part of a selection statement
+
+    This clarifies the substatements of `if consteval` (which has a compound-statement).
+
+commit 2940703c7ee125ce8194f668683ff5b0bbd7791b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jan 2 21:46:02 2022 +0100
+
+    [core] Replace 'enumerated type' with 'enumeration'
+
+    The term "enumerated type" is defined in [enumerated.types]
+    for use in the standard library, and is not synonymous with
+    "enumeration type".
+
+commit a27e5a6ac3a0fc9cb8474b87b92734a923d495c0
+Author: Hubert Tong <hubert-reinterpretcast@users.noreply.github.com>
+Date:   Fri Aug 19 10:36:20 2022 -0400
+
+    [stmt.label, except.pre] Use new wording "control-flow-limited" statement (#5413)
+
+    A new term of art (control-flow-limited statement) is introduced in [stmt.label]
+    to express the restrictions on control flow into a statement (namely jumping to labels).
+    Both [stmt.if] and [except.pre] are updated to use the new term.
+
+    This rewords "shall not be used to" avoiding question of actual "use": the "shall not be
+    used to" phrasing may be taken to refer only in cases where the actual use occurs
+    or is the primary intent. Instead, the intended restriction can be written in terms
+    of static properties of the constructs so restricted in the style of [stmt.if].
+
+commit 5aa000973bba1ce10ce0f4ca6a3bec61bcea2061
+Author: Jason Merrill <jason@redhat.com>
+Date:   Fri Aug 19 10:47:42 2022 -0400
+
+    [lex.charset] Add missing hyphens
+
+    In P2071R2 and NameAliases.txt, 0+008E is named SINGLE-SHIFT-2, but it went
+    into the draft as "single shift-2", losing the hyphen between the words.
+
+commit 8275c19b3fa9e7cb09f84049ebd6207aceb7ca80
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Aug 19 17:29:40 2022 +0100
+
+    [range.cartesian.view] Fix definition of cartesian-product-is-common
+
+    The original wording seems to have been a copy-paste error.
+
+commit 4117a1fc1aeb307d6b15c8aba8a54925fb1b4faf
+Author: Mark de Wever <koraq@xs4all.nl>
+Date:   Fri Aug 19 18:37:58 2022 +0200
+
+    [format.string.escaped] Fix invalid examples
+
+    While implementing new features introduced by P2286R8 Formatting Ranges
+    I noticed some issues in the examples. These issues are in the paper
+    too.
+
+    For s3 the alternative would be to adjust the output instead of the
+    input.
+
+commit 2d548b2ec835510685cf2fcb175f7645aa798d72
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Aug 19 09:35:25 2022 +0100
+
+    [dcl.fct.def.default] Elaborate on the difference of two declarations
+
+    This makes it clear that T_1 and T_2 may differ because of the present
+    rule for the purposes of the blanket statement "other than as allowed
+    by the preceding rules" futher below.
+
+commit d2ad0017c5584825fce1cbf741c160e4bd6108b3
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sun Aug 21 01:22:25 2022 +0800
+
+    [range.chunk.overview,range.slide.overview] Use maths, not code style for N/M (#5500)
+
+commit 1277923e3ac7a35a3713823b5782b57b86f956ed
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sun Aug 21 01:35:35 2022 +0800
+
+    [range.chunk] Fix subclause headings (#5516)
+
+commit 2f228c5cad223a5c8d686d91b054ee3bd2d2a123
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Sun Aug 21 05:01:17 2022 +0800
+
+    [range.as.rvalue.view] Fix accidentally swapped concepts in template head
+
+    Also fixes the whitespace style around the opening brace.
+
+commit 22133b42b1a20d542a8f4d18cc425e8c875e567b
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Aug 20 22:04:26 2022 +0100
+
+    [complex.members] Remove stray "template<class T>" from constructor
+
+    This peculiar presentation had previously worked in conjuction with
+    a subclause on "explicit specializations", but since those explicit
+    specializations have been removed by P1467R9, the template head does
+    not serve any useful purpose any longer.
+
+commit fee56834fb55355d617a88fe764f9fb20d92c329
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Aug 20 22:35:28 2022 +0100
+
+    [expr.prim.lambda.capture] Add cross reference to [basic.scope.lambda]
+
+    Suggested by CD review feedback.
+
+commit 6f70f82eead9ddc10830aedb99286d0db54725ad
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Aug 22 02:11:57 2022 +0800
+
+    [range.repeat.view] Fix typo (#5765)
+
+commit 89df45a30a48f30d2ab367490b47c2c0a87f4aa6
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Aug 22 01:51:41 2022 +0800
+
+    [ranges.cartesian.iterator] Fix typo
+
+commit 35aa22acdf080fc5886d715a965aadd36de28c27
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Aug 21 01:55:27 2022 +0100
+
+    [expr.prim.id.unqual] Fix parameter name in example ("y", not "z")
+
+    The misspelling was a misapplication of the motion paper P2579R0.
+
+    Also harmonize the local use of whitespace.
+
+commit 2841712fc15f831481d7bd39e084c213596ccfec
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Aug 20 23:49:21 2022 +0100
+
+    [vector.syn, vector.bool] Add subclause structure.
+
+    After the addition of the formatting-related specialization, the
+    original subclause contained several class template synopses without
+    any intervening separation. The header synopsis is rearranged to
+    follow the document order.
+
+commit 259b8d5d1beeaccf793783679ff4956e84774ea4
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 00:03:46 2022 +0100
+
+    [alg.sorting.general] Make "comp" part of the defined term
+
+    Suggested by CD review feedback.
+
+commit c2aee77b6413fe8ce09bf816d1e239fa2b93f4a9
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 00:14:49 2022 +0100
+
+    [mdspan.overview] Extend the definition to "size of a MD index space"
+
+    Previously, only "size" was the defined term, but P0009R18 asks for
+    the entire phrase to be the defined term.
+
+    Suggested by CD review feedback.
+
+commit ac27094ee2f367faf32a37008f476d57b19fd999
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 00:29:15 2022 +0100
+
+    [mdspan.extents.expo] Add "exposition-only" comments to itemdecls
+
+    Suggested by CD review feedback.
+
+commit cce4e845272506ad2e0d732d78bce1dcfd02b7c7
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 00:34:32 2022 +0100
+
+    [mdspan.extents.ctor] Consistently use "r" as a maths variable, not code.
+
+    Suggested by CD review feedback.
+
+commit a284ab6c16f387f95adb85e02ad9c07cf36b08a3
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 00:43:14 2022 +0100
+
+    [mdspan.layout.{reqmts,right.ctor}] Consistently use maths, not code
+
+    Suggested by CD review feedback.
+
+commit 62d024620d93fc08611ce9e931fef95c9e064d03
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 00:52:22 2022 +0100
+
+    [mdspan.accessor.reqmts] Replace "pointer" with "data_handle_type".
+
+    This edit was part of LWG Motion 4 (P2604R0) but was accidentally omitted.
+
+commit 9369f4c7f116244193c7c2ed12ecc4a625790776
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 00:56:57 2022 +0100
+
+    [mdspan.layout.stride.expo] Replace "SizeType" with "IndexType".
+
+    This edit was part of LWG Motion 3 (P2599R2) but was accidentally omitted.
+
+commit fd7c919c681630425a48fd01b4c36c631c910303
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 01:01:14 2022 +0100
+
+    [mdspan.layout.stride.{ctor,obs}] Add cross references to [mdspan.layout.policy.reqmts]
+
+    Suggested by CD review feedback.
+
+commit d0c287b45c5b7ec1d5cfffed2eeeed2e2682ed3b
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 09:59:57 2022 +0100
+
+    [flat.multi*] Fix typo ("mutli" => "multi")
+
+commit 06cbf011ea876313132b51f3699b23f942f91123
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 10:13:01 2022 +0100
+
+    [containers] Add cross references to "erasure" subclauses
+
+    In associative containers, the comment in the synopsis is augmented
+    with the name of the class template, since each header contains two
+    class templates (unique and multi).
+
+    Also fixes some index entry spellings.
+
+commit 3b1461021cb81fbbccd27494ecd60de7daf958b8
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Aug 22 17:56:54 2022 +0800
+
+    [range.adaptor.tuple] Fix tuple helper parameter name clash (#5769)
+
+    The code as presented originally was ill-formed.
+
+commit 90c2cfb1fb8e5cb4781a2d8affdc8856279ca09a
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Aug 22 09:32:17 2022 +0800
+
+    [range.repeat.iterator] repeat_view::iterator is not a class template
+
+commit 4762e1b6fa3bcaf4fdc080e2160ab4e9e96f77b6
+Author: A. Jiang <de34@live.cn>
+Date:   Mon Aug 22 15:32:10 2022 +0800
+
+    Fix preconditions for start_lifetime_as_array(p, n)
+
+    "n > 0 is true" can't be in "Mandates:", and it's in "Preconditions:" according to P2590R2.
+
+commit 28f49c965a394c573fa927792f082a182d422029
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Mon Aug 22 19:29:40 2022 +0800
+
+    [range.as.const.view] Fix order of constraints in class synopsis (#5760)
+
+    The header and the class synopses used different orderings in P2446R0,
+    and the ordering from the header synopsis is the desired one.
+
+commit 03d73772246ec6e9fa0becb983be6dc08189d8b1
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 12:23:51 2022 +0100
+
+    [flat.*] Harmonize wording "supports the ... operations but not ..."
+
+commit 9934675dd673bfa8e073bd3c2187575b47e6ea44
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 13:48:45 2022 +0100
+
+    [flat.set.defn] Fix name of function parameter ("rg", not "range")
+
+commit faa173c296bfc3547e6f20af63329ac0e1a024be
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 14:06:39 2022 +0100
+
+    [flat.multiset.ctor] Add missing parameter name "cont"
+
+commit 96fce7b5259e1bfe1688cc60df2d6b2ecf3e7cd1
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 11:49:41 2022 +0100
+
+    [flat.*.{syn,erasure}] Change return type of erase_if to member size_type
+
+    All other containers and container adapters use the member size_type,
+    and the flat maps already did so in the item specification, but not in
+    the synopsis.
+
+    The current wording follows the approved proposals, but this change
+    seems like an improvement.
+
+    Suggested by CD review feedback.
+
+commit 7f11031bf6e41515a8779bdbfe741f4f9bbdfccc
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Aug 20 21:14:55 2022 +0100
+
+    [diff] Uniform style for examples
+
+    For C++ differences, examples are always preceded by the phrase "For
+    example:", do not use the usual [Example n: ... -- end example] style,
+    and always appear in the "Effects on original feature" paragraph.
+
+    For differences with C, a different set of styles is used (examples
+    being part of paragraphs such as "Change" and "Rationale"), and that
+    subclause remains unchanged by this commit.
+
+commit d4280f38ddd489aecd8fb0da17a41f577db42e2a
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Aug 20 23:11:39 2022 +0100
+
+    [memory.syn] Add missing "// freestanding" comment to "destroy"
+
+    The comment was supposed to be added by P1642R11, but was accidentally
+    omitted.
+
+commit 47b0e73cc1e8d2ea344afedf60e07ec80df118f4
+Author: mordante <koraq@xs4all.nl>
+Date:   Mon Aug 22 17:48:36 2022 +0200
+
+    [format.string.std] Reorder std-format-spec field descriptions. (#5246)
+
+    Moves the wording describing the zero-padding before the description of
+    the width; matching the order of the fields in the std-format-spec.
+
+    The original order was introduced in the initial <format> paper P0645R10 "Text Formatting".
+    Since both fields had one paragraph of description, it wasn't too noticeable. P1868R2 "🦄 width:
+    clarifying units of width and precision in std::format" expanded the wording of the width.
+    Now it's not so easy to find the description of the zero-padding field.
+
+commit 517290b26fa8391d3b77d43ca8c271bb92695db7
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 17:06:34 2022 +0100
+
+    [range.cartesian.view] Further fixing of cartesian-product-is-common
+
+    The first fix in 8275c19b3fa9e7cb09f84049ebd6207aceb7ca80 was
+    incorrect. Only Const needs to be dropped (which was an error
+    in the paper), but ignoring Vs... is intentional.
+
+commit 101e7205882495cec1a944c7f6190b08bd131543
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Mon Aug 22 17:23:46 2022 +0100
+
+    [ranges] Add missing closing delimiters
+
+commit 17be256d2431f66842479bf7ab2e92f30fff3060
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jun 18 21:39:06 2022 +0200
+
+    [alg.partitions] Indicate base of logarithm outside big-oh notation
+
+commit c6e83c4dba380b235be59b21db6c54bdffcb997d
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jun 18 21:39:59 2022 +0200
+
+    [set.difference] Fix grammar typo
+
+commit 68e365415c707038f8af6c76f0f6f4cd3a4ce407
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jun 18 21:44:05 2022 +0200
+
+    [uninitialized.move] Fix typos in parameter names
+
+commit c3c6761111cff26e0e742e4d14b5d9e0bd28c4aa
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jun 18 22:53:51 2022 +0200
+
+    [rand.adapt.disc] Remove superfluous trailing semicolon
+
+commit 65c9e5bcb3068a1172a66a7507d26a93adae7981
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jun 18 22:55:17 2022 +0200
+
+    [rand.adapt.ibits] Remove superfluous trailing semicolon
+
+commit 6ede23707505a18cdbb558108d635a0b21a1eeb0
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jun 18 22:55:47 2022 +0200
+
+    [rand.adapt.shuf] Remove superfluous trailing semicolon
+
+commit 5e44bc70b72b64e03e0d09564b2eaf45938a7752
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Jun 18 22:58:11 2022 +0200
+
+    [valarray.members] Fix bad reference to argument
+
+commit 43b2bce231b04c1ccf7dc4bfd20e13f29c0e9c6c
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:29:54 2022 +0200
+
+    [time.duration.io] Fix grammar typo
+
+commit 6e9b678f03a1a4fa8218152596a1952c209d1f27
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:32:40 2022 +0200
+
+    [time.cal.year.members] Fix erroneous qualified-id
+
+commit f0ab64a1dcb5bac1249ff67e838a7f899efeb586
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:39:48 2022 +0200
+
+    [locale.codecvt.general] Remove extra space before template-argument-list
+
+commit bbb7552af35266accf98ae718912579527ee11b8
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:41:58 2022 +0200
+
+    [locale.collate.general] Fix grammar typo
+
+commit 324dfd448ec5b632fc922015414cd206920b5842
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:45:29 2022 +0200
+
+    [ios.base.storage] Fix grammar typo
+
+commit fc53c9ede41d4992dc64f556bc32febb28ad0e1e
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:45:58 2022 +0200
+
+    [fpos] Fix typo in exposition-only member
+
+commit 47273ceb655716f62fc1c9fe00a317b44c221267
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:47:05 2022 +0200
+
+    [fpos.operations] Fix name of type trait
+
+commit 04d7e61e9deaf2481d144e2c0a7d2478cff58764
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jun 19 21:49:00 2022 +0200
+
+    [streambuf.cons] Fix grammar typo
+
+commit f055ba09397bd479317a92c315e5a074f7c2e474
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Apr 17 11:19:04 2022 +0200
+
+    [atomics.syn] Move namespace-scope memory_order_* variables here
+
+commit f400d80927fd580f99f5f2d94c3d07eaa47373d0
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Apr 17 11:23:54 2022 +0200
+
+    [ranges.syn] Move namespace-scope declarations for get(subrange) here
+
+commit e9434db227e8b3113a477dcdd0c6c14ffe2c14b8
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 18:56:41 2022 +0100
+
+    [tuple.creation] Add missing semi-colon to example
+
+commit 25bb0a278e8141613f2c813c50a74428e3da7b8b
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 18:58:39 2022 +0100
+
+    [util.smartptr.shared.obs], [util.smartptr.shared.create] use nullptr for null pointer constant
+
+commit 7a4324c21e4f66af801bc7e7fc78b94119253301
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 21:52:22 2022 +0100
+
+    [char.traits.require] use nullptr for null pointer constant
+
+commit b3b64b35ce456a7e54476b9a00185323b68fcd6d
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 22:01:22 2022 +0100
+
+    [unord.req.general] Use "constant" not "const"
+
+commit a421a3029418651b9734ae786c9b89b72b08b42d
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 22:09:00 2022 +0100
+
+    [unord.multimap.overview] Fix presentation of member types
+
+    As already done in de6b0e70ffe2da0a0f91ce434863202f78c9e029 for unordered_map.
+
+commit a758844278a818fd8ccbd33a6ca0460b31616d74
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 22:33:04 2022 +0100
+
+    [range.elements.view] fix class-key for iterator and sentinel
+
+commit 44b146eda750e453ee3d52587c2accab4be6c74d
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 22:35:18 2022 +0100
+
+    [range.elements.iterator] remove stray semi-colon
+
+commit 3a51f3e858e14abc0623f8823e0d2c883c27a4e4
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 22:45:30 2022 +0100
+
+    [complex.ops] use character literal for single character
+
+commit 678907e6d8af62cab9429b7065be69c36ffa2592
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 22:46:43 2022 +0100
+
+    [rand.req.dist] fix grammar typo
+
+commit 698be9d6b09517dc1323ca99fc4bb84ec62fae9e
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 22:56:42 2022 +0100
+
+    [cons.slice], [gslice.cons] remove undeclared/undocumented copy constructor signatures
+
+commit 1cda1f9d2ac5d8caa81e793ce3f95364aba1fb6b
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Aug 22 23:01:23 2022 +0100
+
+    [template.mask.array.overview], [template.indirect.array.overview] fix itemdecl typos
+
+commit f3ddcf79a971f488b3acf0e52ca6ea9689af7fd7
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Aug 23 19:58:08 2022 +0800
+
+    [ranges.cartesian.iterator] Fix typo "reference_t" => "range_reference_t" (#5777)
+
+commit 227c3b249f0f52484920400b861717649895e6cc
+Author: cor3ntin <corentinjabot@gmail.com>
+Date:   Tue Aug 23 14:00:44 2022 +0200
+
+    [range.adjacent.overview] Use tuple in example, not pair (#5779)
+
+    adjacent_view always yields tuples, but the example was written as if it yielded a std::pair.
+
+commit c0c0d75402b1dc33f0cba971c898dc2ac7bfaa06
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Aug 23 20:00:49 2022 +0800
+
+    [range.cartesian.view] Add missing angle brackets for cartesian-is-sized-sentinel
+
+commit c777f930668fe23ab287ff765463d3b3731696eb
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Aug 23 21:45:23 2022 +0800
+
+    [range.zip, ranges.cartesian.iterator] Simplify `maybe-const<true, Views>` to `const Views` (#5778)
+
+    The type `maybe-const<Const, Views>` only appears after `Const &&`
+    in these cases, so that only the case where `Const` is `true` matters.
+
+commit eca39f43798d7a58fdd482232c60b6db428b656f
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Wed Aug 24 01:57:58 2022 +0800
+
+    [tuple.syn, tuple.like] Fix template head formatting (#5784)
+
+commit 356fb7ff88b63d956b1109c72c5e3bf424f6ba29
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Wed Aug 24 01:58:17 2022 +0800
+
+    [algorithm.syn] Fix template head formatting (#5786)
+
+commit 6ccb959c7a8c10fc5fa7dd469c64f3c992e7e7ee
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Aug 23 20:10:44 2022 +0800
+
+    [range.zip.overview] Use tuple in example, not pair
+
+commit 8404284d8b7ac6ff2725a33d5e33410d1ea3b470
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Tue Aug 23 23:10:39 2022 +0800
+
+    [range.drop.overview, range.take.overview] Fixed unformatted (void)F, decay-copy(E)
+
+commit 6e2b23594abd64c9ba50934654c68bd174c7ab91
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Wed Aug 24 18:49:21 2022 +0800
+
+    [format.range.fmtstr] Add ranges namespace qualifier (#5788)
+
+    The range concept is named outside of the `ranges` namespace.
+
+commit 301f0cdcb547f54b1d39163550a5869a0c6b073f
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Aug 25 02:28:09 2022 +0100
+
+    [coroutine.syn] Move "all freestanding" comment to the top
+
+commit e38650de03741a87d6c625ce93974946f46f5caa
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Aug 25 02:41:49 2022 +0100
+
+    [tuple.like] Remove extraneous "std::" qualification.
+
+commit 3da6b0e8798681144b676b3b4180301f8f7c8f2c
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Aug 25 10:55:25 2022 +0100
+
+    [const.iterators.{alias,iterators}] Add "exposition only" comments
+
+    Suggested by CD review feedback.
+
+commit 5dd0216a477391fbce339e22f169136420472979
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Aug 25 11:12:24 2022 +0100
+
+    [range.refinements] Fix template argument name ("T", not "R")
+
+commit 347ded018d09d2a226e3ab42665d1a13b25d489a
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Aug 25 11:27:38 2022 +0100
+
+    [vector.bool.pspc] Reinstate redundant "inline", as per paper
+
+    The "inline" was removed editorially in
+    2141dab25c7f6d186d662e0ebe916efcd56843ae, but CD review has requested
+    we retain it.
+
+commit 79ab62930d2538e1ef668c6a1b50e8d7027ebedc
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Aug 25 11:34:57 2022 +0100
+
+    [format.string.escaped] Fix typos in "APOSTROPHE"
+
+commit 426ce8a7ec2232aebaaf76bf2f5e4a69a500cef6
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Thu Aug 25 19:31:57 2022 +0800
+
+    [ranges] Tweak some examples (#5791)
+
+    Removes redundant `std::` qualifications and uses `views::meow` instead of `meow_view`.
+
+commit 4ed7fcf6b725207ac307a6d1411ad2aa4ed55c8f
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Aug 26 04:36:08 2022 +0800
+
+    [containers] Add `std::` for `forward`/`move` (#5793)
+
+commit aec46d1970a8869db0d178c436545b0e40968425
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Aug 26 04:43:03 2022 +0800
+
+    [move.sentinel] Remove extraneous "std" qualification in example (#5792)
+
+commit ed18148b1d514c0aea12d99b1ec3a56d4a834266
+Author: Hewill Kang <67143766+hewillk@users.noreply.github.com>
+Date:   Fri Aug 26 15:00:12 2022 +0800
+
+    [util.smartptr.shared.create] Add std:: qualification for forward
+
+commit eb703517cd6c79f56df12c5dca359121efbef4ee
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Aug 26 14:39:39 2022 +0100
+
+    [range.move.wrap] Fix constraint (move, not copy-constructible)
+
+    This was accidentally omitted from previous changes requested by P2494R2.
+
+commit 2a600822d08332a8350e3a093212bdc7f8a82e2b
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Aug 26 15:06:06 2022 +0100
+
+    [format.range.fmtdef] Add "exposition only" comments
+
+commit 9d71b7d3b0aac1f179fc3973b0ff1624b00b07ce
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Aug 26 15:26:39 2022 +0100
+
+    [obj.lifetime] Add cross-reference pointing at basic.types.general
+
+    Suggested by CD review feedback.
+
+commit 9eb92bf36b19381a534273ad98e296dfeb7a0fc9
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Aug 29 22:45:41 2022 +0200
+
+    [flat.set.modifiers] Remove stray 'return' in Effects clause
+
+commit 69177109f387d3958ffea237c9b0419e4d2aa49c
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Fri Sep 2 23:44:14 2022 +0100
+
+    [expr.ass] Fix typo, "~" should be "^".
+
+    This was a misapplication of P2327R1 in 0aebf5cacded1b64cf089dbc7a0504fbb9f50aa6.
+
+commit e6e17d5e136934f113d6e0a8bde4c227459a9d47
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Sep 3 02:10:27 2022 +0100
+
+    [diff.cpp20.{dcl,expr}] Fix subclause order to match main document
+
+commit 853747c5d8130880b96a39ab940c343aa7530d71
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sat Sep 3 15:02:00 2022 +0100
+
+    [basic.fundamental] Use correct number; "are", not "is".
+
+commit 07e02a80fe890dcb6e84182a5697046f1bd4c630
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Aug 29 22:23:54 2022 +0200
+
+    [expected.object.assign] Add missing 'Returns: *this'
+
+commit 06dcf0556631382ecdc420c22c66366168c226b4
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 13:01:12 2022 +0100
+
+    [mdspan.layout.left.overview] Reorder "explicit" and "constexpr"
+
+    The standard ordering is "constexpr explicit", not the other way
+    round. The paper P0009R18 contains a non-standard style, and other
+    instances had already been fixed. Only this one seems to have been
+    missed previously.
+
+commit e651f145df7c587ea810aca754e680bb27ea8481
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 13:08:42 2022 +0100
+
+    [mdspan.layout.{left,right}.overview] Replace "see below" with condition
+
+    The condition is spelled out in the item descriptions already, and the
+    class synopses seem to simply have been inconsistent with that in the
+    incoming paper P0009R18. Since the "see below"s are never referenced
+    explicitly, we just replace them with the actual conditions, which is
+    also how the surrounding members are presented.
+
+commit 1765844a9382e1f3415bbbdcd12eaa09a6b1f827
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 13:25:52 2022 +0100
+
+    [mdspan.layout.stride.expo] Move "otherwise" from trailing to leading
+
+    We have a mild preference for the leading position.
+
+commit c02512ecf3f15fb0f29dc602eb153bc7dabd643d
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 13:53:01 2022 +0100
+
+    [mdspan.layout.stride.obs] Add missing parentheses
+
+commit 9897c566ec3ecd6f25078a3dd10ce34c17e812e7
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 13:54:19 2022 +0100
+
+    [mdspan.accessor.default.members] Fix typo in "equivalent"
+
+commit 3b6163d1a3b1f5cc2be49d6ff0eb6b3889b552df
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 13:58:09 2022 +0100
+
+    [flat.map.syn] Add missing "namespace std {"
+
+commit c164add6cdac73cae85649ba2172de43c3d8ed5b
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 14:02:11 2022 +0100
+
+    [flat.map.modifiers] Typo: "range" should be "rg"
+
+commit 1b427b20fecbc95b98d2380e0ddae71b71c1f657
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Sun Sep 4 14:06:53 2022 +0100
+
+    [flat.{,multi}set.ctor] Add missing "explicit" in itemdecls
+
+commit 8f153df9c66c33f100ec7a4d7998dfaf6a7aa8da
+Author: Thomas Köppe <tkoeppe@google.com>
+Date:   Thu Nov 26 02:43:37 2020 +0000
+
+    [basic, except, diff] Rewordings to avoid "might" and "could"
+
+ + diff --git a/papers/n4918.md b/papers/n4918.md new file mode 100644 index 0000000000..550414f120 --- /dev/null +++ b/papers/n4918.md @@ -0,0 +1,1874 @@ +# N4918 Editors' Report -- Programming Languages -- C++ + +Date: 2022-09-06 + +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 most of the draft +motion applications, and to Hewill Kang for spotting and sending corrections for +many editorial issues. + +## New papers + + * [N4917](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/n4917.pdf) is the + current working draft for C++23. It replaces + [N4910](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/n4910.pdf). + * N4918 is this Editors' Report. + * N4919 is the C++23 Committee Draft. + +## Motions incorporated into working draft + +### Core working group polls + +CWG poll 1: Accept as Defect Reports all issues except 2507 and 2586 in +[P2622R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2622r0.html) +(Core Language Working Group "ready" Issues for the July, 2022 meeting) and +apply their proposed resolutions to the C++ Working Paper. + +CWG poll 2: Apply the proposed resolution of issues 2507 and 2586 in +[P2622R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2622r0.html) +(Core Language Working Group "ready" Issues for the July, 2022 meeting) to the +C++ Working Paper. + +CWG poll 3: Accept as a Defect Report and apply the changes in +[P2468R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2468r2.html) +(The Equality Operator You Are Looking For) to the C++ Working Paper. + +CWG poll 4: Accept as a Defect Report and apply the changes in +[P2327R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2327r1.pdf) +(De-deprecating volatile compound operations) to the C++ Working Paper. + +CWG poll 5: Apply the changes in +[P2437R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2437r1.pdf) +(Support for `#warning`) to the C++ Working Paper. + +CWG poll 6: Apply the changes in +[P2362R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2362r3.pdf) +(Remove non-encodable wide character literals and multicharacter wide character +literals) to the C++ Working Paper. + +CWG poll 7: Apply the changes in +[P2324R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2324r2.pdf) +(Labels at the end of compound statements (C compatibility)) to the C++ Working +Paper. + +CWG poll 8: Apply the changes in +[P2290R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2290r3.pdf) +(Delimited escape sequences) to the C++ Working Paper. + +CWG poll 9: Apply the changes in +[P2448R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html) +(Relaxing some `constexpr` restrictions) to the C++ Working Paper. + +CWG poll 10: Apply the changes in +[P2266R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2266r3.html) +(Simpler implicit move) to the C++ Working Paper. + +CWG poll 11: Apply the changes in +[P2071R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2071r2.html) +(Named universal character escapes) to the C++ Working Paper. + +CWG poll 12: Apply the changes in +[P1169R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1169r4.html) +(static `operator()`) to the C++ Working Paper. + +CWG poll 13: Accept as a Defect Report and apply the changes in +[P2280R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2280r4.html) +(Using unknown pointers and references in constant expressions) to the C++ +Working Paper. + +CWG poll 14: Apply the changes in +[P1467R9](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1467r9.html) +(Extended floating-point types and standard names) to the C++ Working Paper. + +CWG poll 15: Accept as a Defect Report +[P2493R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2493r0.html) +(Missing feature test macros for C++20 core papers). (The paper was already +adopted at the February, 2022 meeting, and no changes to the Working Paper +result from it now.) + +CWG poll 16: Apply the changes in +[P2582R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2582r1.pdf) +(Wording for class template argument deduction from inherited constructors) to +the C++ Working Paper. + +CWG poll 17: Apply the changes in +[P1774R8](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1774r8.pdf) +(Portable assumptions) to the C++ Working Paper. + +CWG poll 18: Apply the changes in +[P2295R6](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2295r6.pdf) +(Support for UTF-8 as a portable source file encoding) to the C++ Working Paper. + +CWG poll 19: Accept as a Defect Report and apply the changes in +[P2513R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2513r3.html) +(`char8_t` Compatibility and Portability Fix) to the C++ Working Paper. + +CWG poll 20: Accept as a Defect Report and apply the changes in +[P2460R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2460r2.pdf) +(Relax requirements on `wchar_t` to match existing practices) to the C++ Working +Paper. + +CWG poll 21: Accept as a Defect Report and apply the changes in +[P2579R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2579r0.pdf) +(Mitigation strategies for P2036 "Changing scope for lambda +trailing-return-type") to the C++ Working Paper. + +### Library working group polls + +LWG poll 1: Apply the changes for all Ready issues in +[P2618R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2618r0.html) (C++ +Standard Library Issues to be moved in Virtual Plenary, Jul. 2022) to the C++ +working paper. + +LWG poll 2: Apply the changes in +[P0009R18](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0009r18.html) +(MDSPAN) to the C++ working paper. + +LWG poll 3: Apply the changes in +[P2599R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2599r2.pdf) +(`index_type` & `size_type` in `mdspan`) to the C++ working paper. + +LWG poll 4: Apply the changes in +[P2604R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2604r0.html) +(`mdspan`: rename `pointer` and `contiguous`) to the C++ working paper. + +LWG poll 5: Apply the changes in +[P2613R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2613r1.html) (Add +the missing `empty` to `mdspan`) to the C++ working paper. + +LWG poll 6: Apply the changes in +[P0429R9](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0429r9.pdf) (A +Standard `flat_map`) to the C++ working paper. + +LWG poll 7: Apply the changes in +[P1222R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1222r4.pdf) (A +Standard `flat_set`) to the C++ working paper. + +LWG poll 8: Apply the changes in +[P1223R5](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1223r5.pdf) +(`find_last`) to the C++ working paper. + +LWG poll 9: Apply the changes in +[P1642R11](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1642r11.html) +(Freestanding Library: Easy [utilities], [ranges], and [iterators]) to the C++ +working paper. + +LWG poll 10: Apply the changes in +[P1899R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1899r3.html) +(`stride_view`) to the C++ working paper. + +LWG poll 11: Apply the changes in +[P2093R14](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2093r14.html) +(Formatted output) to the C++ working paper. + +LWG poll 12: Apply the changes in +[P2165R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2165r4.pdf) +(Compatibility between `tuple`, `pair` and _tuple-like_ objects) to the C++ +working paper. + +LWG poll 13: Apply the changes in +[P2278R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2278r4.html) +(`cbegin` should always return a constant iterator) to the C++ working paper. + +LWG poll 14: Apply the changes in +[P2286R8](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2286r8.html) +(Formatting Ranges) to the C++ working paper. + +LWG poll 15: Apply the changes in +[P2291R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2291r3.pdf) (Add +Constexpr Modifiers to Functions `to_chars` and `from_chars` for Integral Types +in `` Header) to the C++ working paper. + +LWG poll 16: Apply the changes in +[P2302R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2302r4.html) +(`std::ranges::contains`) to the C++ working paper. + +LWG poll 17: Apply the changes in +[P2322R6](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2322r6.html) +(`ranges::fold`) to the C++ working paper. + +LWG poll 18: Apply the changes in +[P2374R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2374r4.html) +(`views::cartesian_product`) to the C++ working paper. + +LWG poll 19: Apply the changes in +[P2540R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2540r1.html) +(Empty Product for certain Views) to the C++ working paper. + +LWG poll 20: Apply the changes in +[P2404R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2404r3.pdf) +(Move-only types for `equality_comparable_with`, `totally_ordered_with`, and +`three_way_comparable_with`) to the C++ working paper. + +LWG poll 21: Apply the changes in +[P2408R5](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2408r5.html) +(Ranges iterators as inputs to non-Ranges algorithms) to the C++ working paper. + +LWG poll 22: Apply the changes in +[P2417R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2417r2.pdf) (A +more constexpr bitset) to the C++ working paper. + +LWG poll 23: Apply the changes in +[P2419R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2419r2.html) +(Clarify handling of encodings in localized formatting of chrono types) to the +C++ working paper. + +LWG poll 24: Apply the changes in +[P2438R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2438r2.html) +(`std::string::substr() &&`) to the C++ working paper. + +LWG poll 25: Apply the changes in +[P2446R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2446r2.html) +(`views::as_rvalue`) to the C++ working paper. + +LWG poll 26: Apply the changes in +[P2465R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2465r3.pdf) +(Standard Library Modules `std` and `std.compat`) to the C++ working paper. + +LWG poll 27: Apply the changes in +[P2445R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2445r1.pdf) +(`std::forward_like`) to the C++ working paper. + +LWG poll 28: Apply the changes in +[P2467R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2467r1.html) +(Support exclusive mode for fstreams) to the C++ working paper. + +LWG poll 29: Apply the changes in +[P2474R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2474r2.html) +(`views::repeat`) to the C++ working paper. + +LWG poll 30: Apply the changes in +[P2494R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2494r2.html) +(Relaxing range adaptors to allow for move only types) to the C++ working paper. + +LWG poll 31: Apply the changes in +[P2499R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2499r0.html) +(`string_view` range constructor should be `explicit`) to the C++ working paper. + +LWG poll 32: Apply the changes in +[P2502R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2502r2.pdf) +(`std::generator`: Synchronous Coroutine Generator for Ranges) to the C++ working +paper. + +LWG poll 33: Apply the changes in +[P2508R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2508r1.html) +(Exposing std::basic-format-string<charT, Args...>) +to the C++ working paper. + +LWG poll 34: Apply the changes in +[P2517R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2517r1.html) (Add +a conditional `noexcept` specification to `std::apply`) to the C++ working paper. + +LWG poll 35: Apply the changes in +[P2520R0](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2520r0.html) +(`move_iterator` should be a random access iterator) to the C++ working +paper. + +LWG poll 36: Apply the changes in +[P2549R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2549r1.html) +(`std::unexpected` should have `error()` as member accessor) to the C++ +working paper. + +LWG poll 37: Apply the changes in +[P2585R1](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2585r1.html) +(Improving default container formatting) to the C++ working paper. + +LWG poll 38: Apply the changes in +[P2590R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2590r2.pdf) +(Explicit lifetime management) to the C++ working paper. + +## Editorial changes + +### Notes on motions + +* **Poll CWG-9:** The wording was based on an old draft, and has been adjusted + to integrate with the current draft: an additional example that was added by + [P2242R3](http://open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2242r3.html) + has also been deleted. + +* **Polls CWG-12 and LWG-1:** The wording from issue + [LWG-3617](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2618r0.html#3617) + has been integrated with the wording of, and guided by advice from, + [P1169R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1169r4.html). + +* **Poll LWG-2:** Several minor changes were made to this long paper + [P0009R18](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0009r18.html), + "`mdspan`": The expression `sizeof...(OtherSizeTypes)` was given the name `N` + in a few places to simplify the presentation; the phrase "for all rank index + `r`" was changed to "for every rank index `r`", notes have been reworded to + avoid the modal verb "may". + +* **Polls LWG-8 and LWG-1:** The macro `ATOMIC_FLAG_INIT` from + [LWG-3659](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2618r0.html#3659) + has also been marked "freestanding". + +* **Poll LWG-14:** Range formatting is also specified for the new "flat" + container adaptors, as requested by + [P2286R8](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2286r8.html). + +* **Poll LWG-29:** Minor errors in + [P2474R2](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2474r2.html) + ("`views::repeat`") have been corrected. + +* **Poll LWG-33:** The changes have also been applied to new wording from + LWG-11. + +* **Poll LWG-34:** The changes have been integrated with the earlier changes + from LWG-12 + ([P2165R4](http://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2165r4.pdf), + "Compatibility between `tuple` and tuple-like objects"). + +* **Polls LWG-14, -23, -33, -37:** All four papers ask to update the + `__cpp_lib_format` feature test macro. This has since been discussed and found + unsatisfactory, but a resolution will only be applied editorially in the next + working draft. + +### Noteworthy editorial changes + +* We introduced the new term "_control-flow-limited_ statement" in [stmt.label] + to refer to a statement into which one cannot jump from the outside, which is + used for constexpr if, consteval if, and try and catch blocks. + +* Additional subclauses have been introduced where needed to ensure that there + is only one class synopsis along with its member specifications per subclause, + so as to not be ambiguous. Apart from modifying the current motions, this + affects [vector.bool]. + +* Extraneous subclauses were removed, and their contents flattened, from the + erstwhile [expected.un.object]. + +* Old wording for container adapters that used to say "other kinds of sequence + containers that the user defines" has been replaced with "other program-defined + sequence containers", since we now need this phrase in two places, and the term + "program-defined" was only introduced recently. + +* Further rewordings have been made to avoid the use of the "might" and "could" + modal verbs in notes. + +### Minor editorial changes + +A log of editorial fixes made to the working draft since N4910 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/n4910...n4917). + + commit fb8135e5ec22acd26cb0dcb1bface21eee118895 + Author: hewillk <67143766+hewillk@users.noreply.github.com> + Date: Sun Mar 6 20:22:18 2022 +0800 + + [range.utility.conv.general] Add missing template parameter to container-inserter + + commit b7c1f9a77eac8dfeb4cb2e92bd3b2a57d05c298a + Author: Jens Maurer + Date: Fri Mar 25 09:37:42 2022 +0100 + + [spanbuf] Fix template name in subclause heading (#5365) + + commit cdca862605ae315e2d7a1ca7c7c1b011651944d2 + Author: Jens Maurer + Date: Fri Mar 25 10:44:58 2022 +0100 + + [span.streams] Move non-member swaps to header synopsis (#5366) + + commit 478b8f8807e5b4561874842aa24a132558682f00 + Author: A. Jiang + Date: Thu Mar 31 19:34:03 2022 +0800 + + [alg.min.max] Consistently specify ranges::minmax_element with minmax_element_result (#5376) + + LWG3180 was incompletely applied with commit e33be08f8ca49a9a139aa81b7a1ba9787d85f4fc. + + commit c92196bc67e252f06907c6de44173ce7157d71df + Author: Jens Maurer + Date: Fri Apr 1 13:38:03 2022 +0200 + + [memory.syn] Add missing closing bracket for attribute + + commit 1d2d223ab9fee202b67b31b32b85f44e3f9dc187 + Author: hewillk <67143766+hewillk@users.noreply.github.com> + Date: Thu Mar 24 02:13:51 2022 +0800 + + [range.adjacent.transform.iterator] Fix wrong template parameter in adjacent_transform_view::iterator + + commit 4813f202b3e2f6d0062967b9fd96ca54b91c7b65 + Author: Jens Maurer + Date: Wed Mar 30 08:29:55 2022 +0200 + + [stacktrace.syn] Add '#include ' + + LWG3330 added #include to all header files + where a three-way comparison operator was declared, + but missed this one. + + commit d9040a775aa528f0576453532f3cb5058a6e6f24 + Author: A. Jiang + Date: Wed Apr 6 20:03:39 2022 +0800 + + [allocator.requirements.general] Specify all member types with typename (#5386) + + commit 2bfa7c4cc96203e03763816cf310e54e5b8940bb + Author: Daniel Krügler + Date: Fri Apr 15 21:26:27 2022 +0200 + + [temp.constr.normal] Add missing semicolon in example (#5395) + + commit a8dbfc63227bf596dcf72a31c9fef4af8af9e592 + Author: Jonathan Wakely + Date: Wed Apr 20 14:41:22 2022 +0100 + + [depr.tuple,depr.variant] Use struct class-key consistently (#5402) + + commit 4fc805d949bfc99ee6cfcf666123eb982fc4c465 + Author: Jens Maurer + Date: Thu Apr 21 09:27:57 2022 +0200 + + [expr.prim.lambda.general] Clarify deduced lambda return type + + commit 5fb0fd092782f57e8395841470c92176412a10a3 + Author: Jonathan Wakely + Date: Thu Mar 24 09:29:07 2022 +0000 + + [expected.un.object.general] Reorder constructors in synopsis + + This matches the order in [expected.un.ctor]. + + commit 8e7a9b9fbf2f7a7dfa913a77068b6a6d3488e521 + Author: Jonathan Wakely + Date: Thu Mar 24 09:36:55 2022 +0000 + + [expected.un.object] Remove unnecessary subclause nesting + + All the other class templates in are at the rSec3 level, but + std::unexpected is below a mostly useless rSec3 [expected.unexpected]. + This subclause has two children, [expected.un.general] which is a single + sentence, and [expected.un.object] which defines the class template and + its members. If we merge the single sentence from [expected.un.general] + into the same subclause as the class synopsis then we can get remove the + unnecessary nesting. As a nice side effect, this also gets rid of + "object" in the [expected.un.object] stable name, which doesn't really + make sense in context. + + commit 3372ed0572fd8aa59ed9e59432cd8f593868be49 + Author: Casey Carter + Date: Mon Apr 25 13:24:24 2022 -0700 + + [range.utility.conv.general] Strike extraneous semicolon (#5414) + + commit 4b7deb009c4dfbbe8f2c879f764be446f94957b2 + Author: xmh0511 <970252187@qq.com> + Date: Tue Apr 26 04:26:19 2022 +0800 + + [lex.ccon] Fix typo in character name for U+0027 (#5412) + + commit 93de6031da2ef99b402e18ee8941fd6c7b554ce4 + Author: Jens Maurer + Date: Tue Apr 26 14:14:02 2022 +0200 + + [string.view.deduct] Move to immediately after [string.view.cons] (#5397) + + commit 41bc0c2ab38c32638685ef9a5068e06abbfc07f3 + Author: hewillk <67143766+hewillk@users.noreply.github.com> + Date: Tue Apr 26 20:16:26 2022 +0800 + + [expected] Add missing noexcept for expected::error() (#5381) + + commit b075835f134e4956fe27eaa5323655137aff3d45 + Author: Hui <65944694+huixie90@users.noreply.github.com> + Date: Tue Apr 26 18:56:30 2022 +0100 + + [iterator.concept.readable] Remove obsolete note (#5408) + + The note was obsoleted by P1878R1. + + commit eed51157b2011478eb40254fbf191f2dd5fca7ca + Author: hewillk <67143766+hewillk@users.noreply.github.com> + Date: Tue May 3 15:26:39 2022 +0800 + + [expected.object.general] Remove explicit keyword for copy/move constructors (#5380) + + commit d23b318949c0a74c6f93f50afb1375ba9eb7aefd + Author: Jonathan Wakely + Date: Wed May 4 00:50:55 2022 +0100 + + [stringbuf.virtuals] add "override" to setbuf + + commit fbe06e9076db0116e395e969f4cb921e45ae964a + Author: Jonathan Wakely + Date: Wed May 4 00:51:45 2022 +0100 + + [adjacent.difference] fix grammar typo + + commit bb8729f3cba593b963031bb25a1a4f12e12ad4fb + Author: Jonathan Wakely + Date: Wed May 4 00:52:40 2022 +0100 + + [streambuf.virt.get] fix grammar typo + + commit 6fa045bf939eeff4dcea56e1a84ab7e1aac69f78 + Author: Jonathan Wakely + Date: Wed May 4 01:12:12 2022 +0100 + + [thread.lock.unique.cons] Use nullptr for null pointer constant + + commit f6791f7f9346c007921fec0b406a9edcbf667951 + Author: Jens Maurer + Date: Wed May 4 11:55:03 2022 +0200 + + [syncstream.osyncstream.cons] Fix use of parameter name (#5445) + + commit 74ad79739e2a13022bc6a33ff2e32efe59a47578 + Author: Jens Maurer + Date: Wed May 4 11:55:45 2022 +0200 + + [thread.sema.cnt] Add missing parentheses on function call expression (#5443) + + commit 8147026d04fe8fb44ed439cea950b5dab136c04c + Author: Jens Maurer + Date: Wed May 4 11:56:14 2022 +0200 + + [cons.slice] Add copy constructor for 'slice' to synopsis (#5444) + + commit fb379c19180d1e26b2b8146d547bcc84c59a0da5 + Author: Jens Maurer + Date: Wed May 4 11:56:50 2022 +0200 + + [over.match.best.general] Fix typo in example (#5446) + + commit 81e506da21960bc70c271f775673a311ec957f6b + Author: Casey Carter + Date: Wed May 4 02:59:27 2022 -0700 + + [ranges.syn] remove trailing `-> see below` return type from three `to` overloads (#5419) + + Since there is actually no return type specification to see below in [range.utility.conv]. + + commit 11d886b5c6062ec7291469514eb07424811e4f65 + Author: languagelawyer <38548419+languagelawyer@users.noreply.github.com> + Date: Tue Apr 26 17:39:39 2022 +0300 + + [class.access] Remove dangling Note + + Invalidated by P1847R4 + + commit 5032e88247bafb5c44dcd4d8ac2ffe3f8bff1bd9 + Author: Jens Maurer + Date: Sat Apr 23 22:15:46 2022 +0200 + + [associative] Add "i.e." in front of explanation + + commit 445d18255713e183df2819e565aa5faa7f85bb1d + Author: hewillk <67143766+hewillk@users.noreply.github.com> + Date: Fri Apr 1 22:46:44 2022 +0800 + + [range.utility.conv.general] Add missing constexpr for container-inserter + + commit 64969e2057ef55b7ac3db8e23c37547edff5c8cf + Author: Jens Maurer + Date: Thu May 5 13:14:25 2022 +0200 + + [intro.memory] Fix missing semicolon in example + + commit dcf0f144f72e8116c59c188c5057a6ca8a7615d3 + Author: Jens Maurer + Date: Thu May 5 13:35:33 2022 +0200 + + [intro.progress] Fix grammar typo + + commit 8c743eacc4b8609650d690b774f855507bd0846f + Author: Jens Maurer + Date: Thu May 5 13:41:54 2022 +0200 + + [expr.prim.lambda.general] Fix missing capture-default in example + + commit 359b8f41027c970bbbc63f1319a890adaa338f6f + Author: Jens Maurer + Date: Thu May 5 16:59:35 2022 +0200 + + [expr.await] Fix English grammar in string-literal in example + + commit 117b352d584cac601c22c63328355658271a6f17 + Author: Jens Maurer + Date: Thu May 5 17:05:50 2022 +0200 + + [expr.xor] Fix grammar typo + + commit 980aded4060cb408c053b0ee4620a71f3b6b73c6 + Author: Jens Maurer + Date: Thu May 5 17:06:01 2022 +0200 + + [expr.or] Fix grammar typo + + commit edb43d00ec4f5e98d45c03408b5d0be6b0484c27 + Author: Jens Maurer + Date: Thu May 5 17:09:06 2022 +0200 + + [expr.yield] Fix typos in examples + + commit 451d8b95bd4c04bf89a5915eb973f837873c432b + Author: Jens Maurer + Date: Thu May 5 17:20:11 2022 +0200 + + [dcl.fct.default] Fix grammar typo in comment in example + + commit cd2690e9ace12f901acce1c1e9157f5cbbf06b24 + Author: Jens Maurer + Date: Thu May 5 17:21:32 2022 +0200 + + [dcl.init.aggr] Fix grammar typo in example + + commit cbc1a36376f32e9d31d5276ba44d8237d0632c37 + Author: Jens Maurer + Date: Thu May 5 17:24:29 2022 +0200 + + [dcl.fct.def.coroutine] Fix grammar typo + + commit d7be2ebee9dd3df849cf87bed768f9bb9f8684f8 + Author: Jens Maurer + Date: Thu May 5 17:27:11 2022 +0200 + + [class.copy.ctor] Fix grammar typo + + commit 4284e8c31673912ae92bc210bb39aa4b05f0ed86 + Author: Jens Maurer + Date: Thu May 5 17:31:25 2022 +0200 + + [class.expl.init] Fix grammar typo + + commit 6c0d1411779d9e2c3e9a59d10b09605b6e5f1482 + Author: Jens Maurer + Date: Thu May 5 17:35:00 2022 +0200 + + [class.base.init] Fix grammar typo in note + + commit 40483ba8cff2165cd81dd75718559037af3ecaa8 + Author: Jens Maurer + Date: Thu May 5 22:43:03 2022 +0200 + + [over.match.class.deduct] Fix syntax error in example + + commit 04cb8da6485b09592008c82eb330125fbf1034cd + Author: Jens Maurer + Date: Thu May 5 23:15:42 2022 +0200 + + [temp.decls.general] Fix missing comma + + commit e6633adbb2f3a6590cd75a000b377c8736c65094 + Author: Jens Maurer + Date: Fri May 6 00:17:50 2022 +0200 + + [temp.deduct.type] Fix grammar typo + + commit 1386c5b2cf41b713a12f526077eb578b68bacb9b + Author: Jens Maurer + Date: Fri May 6 00:19:23 2022 +0200 + + [temp.over] Fix grammar typos + + commit 21dc6d863a5acb0c3e5ec008bddb1c02b3dcd29a + Author: hewillk <67143766+hewillk@users.noreply.github.com> + Date: Thu May 19 11:23:47 2022 +0800 + + [range.join.view] Simplify range_reference_t to InnerRng + + I think this is a reasonable simplification and also makes it consistent with join_with_view. + + commit 2101d81b42bfcb7ab2227617a5ebe86e0b5733e8 + Author: Casey Carter + Date: Mon May 23 04:39:15 2022 -0700 + + [expected.object.ctor] Use the injected-class-name to refer to the current instantiation (#5485) + + ... as is conventional in library wording. + + commit 31be778d39b144fe867e24d80481786ad012661e + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sun May 29 04:51:06 2022 +0800 + + [ranges] Remove redundant "exposition only" comments in \itemdecl (#5499) + + commit aff22aca63d0fb4b183cf073de8abfd4b9bb22bd + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Jun 10 00:24:11 2022 +0800 + + [range.istream.view] Add reference for basic_istream_view::iterator (#5514) + + commit 10a20b22491f1ff39a47847a68c9e4a648754d10 + Author: Mathias Stearn + Date: Thu Jun 9 18:52:42 2022 +0200 + + [res.on.functions] Use regular "behavior is undefined" words of power (#5513) + + commit 4bfa5ddf04586b6df76e0f44e4cde8b59f4a0401 + Author: Casey Carter + Date: Thu Jun 9 09:56:29 2022 -0700 + + [range.istream.iterator] basic_istream_view::iterator is not a class template (#5515) + + commit f73087971183d1daa992ad5165946609a77d39ff + Author: Jens Maurer + Date: Sun Jun 12 16:18:19 2022 +0200 + + [func.wrap.move.ctor] Fix typo naming template parameter packs (#5517) + + commit 8d3f43888013437a2870877f00f017860b083df4 + Author: Johel Ernesto Guerrero Peña + Date: Sat Jun 11 17:34:09 2022 -0400 + + [range.adjacent.iterator] Use correct descriptive element + + commit d86e1ef9ef8514e570fdbbc5038f71e272dbb008 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sun Jun 12 03:11:07 2022 +0800 + + [ranges.syn] Fix the constraints order of slide_view + + commit c4a46fb7343c591f8844c2615ec25cfe8021656a + Author: hewillk <67143766+hewillk@users.noreply.github.com> + Date: Sat May 21 20:39:59 2022 +0800 + + [move.iter.cons] Add missing Returns + + commit 45498df90fa8fa6ffb4de7341c65a2924de9879c + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Thu Jun 16 04:57:27 2022 +0800 + + [range.join.with.sentinel] Add missing curly brace (#5530) + + commit d78d53f96d076f66a8af4ca7e71ae48e1d0596be + Author: Jens Maurer + Date: Thu Jun 16 13:52:29 2022 +0200 + + [allocator.adaptor.syn] Fix typo in comment in header synopsis + + commit 01f16bc99a6a89e69b7a6ec5ae8bfe307ec5299a + Author: Jens Maurer + Date: Thu Jun 16 17:33:52 2022 +0200 + + [functional.syn,func.search.default] Fix name of template parameter + + commit 0678f9986b2c1f75e55d596f63876979433522d4 + Author: Jens Maurer + Date: Thu Jun 16 17:43:07 2022 +0200 + + [meta.rel] Add parentheses for consistency + + Parentheses are used for is_pointer_interconvertible_base_of. + + commit c8a496c62d973305cd6eb5a23d80f169062335fc + Author: Jens Maurer + Date: Thu Jun 16 17:51:57 2022 +0200 + + [string.view.general] Add missing template-argument-list + + commit 70d07925ad874144f2dae4359f5a17c6cada1cdb + Author: Jens Maurer + Date: Thu Jun 16 17:55:30 2022 +0200 + + [forward.list.modifiers] Fix misspelled parameter name + + commit 66fd28de5c730a271bcf631f8452048c0e709232 + Author: Jens Maurer + Date: Thu Jun 16 17:56:48 2022 +0200 + + [set.cons] Fix grammar typo + + commit de6b0e70ffe2da0a0f91ce434863202f78c9e029 + Author: Jens Maurer + Date: Thu Jun 16 18:00:21 2022 +0200 + + [unord.map.overview] Fix presentation of member types + + commit 5be153e248d9e741c841ff3ab6c2e3714ecba24b + Author: Jens Maurer + Date: Fri Jun 17 08:14:19 2022 +0200 + + [unord.set.overview] Fix presentation of member types + + commit 633178f3fd48a784a96a6610f6b12c10700603c0 + Author: Jens Maurer + Date: Fri Jun 17 08:15:22 2022 +0200 + + [unord.multiset.overview] Fix presentation of member types + + commit 5ae534c0c522cf661d3e94c58f54c7d37cf7905a + Author: Jens Maurer + Date: Fri Jun 17 08:18:34 2022 +0200 + + [random.access.iterators] Add semicolon at end of statement + + commit f60caf420b5210f0ad284999a1e471d50c424856 + Author: Jens Maurer + Date: Fri Jun 17 08:21:11 2022 +0200 + + [range.req.general] Fix grammar typo + + commit 75436ee3dd005cf13153ee05c9174a3a3df0054d + Author: Jens Maurer + Date: Fri Jun 17 08:32:31 2022 +0200 + + [range.take.view] Replace 'struct' with 'class' for consistency + + commit 8738cac27de2d66addf735f4fc2b370b73bb9ecc + Author: Jens Maurer + Date: Fri Jun 17 08:33:59 2022 +0200 + + [range.take.while.overview] Highlight use of ranges::begin + + commit 51cad172464c89cc14fff19d87d6bba6bc68f61d + Author: Jens Maurer + Date: Fri Jun 17 08:38:54 2022 +0200 + + [algorithms.requirements] Add commas for readability + + commit 5096e87c6c882ae2aff40c3558db7c2ec95ff4a8 + Author: Jens Maurer + Date: Fri Jun 17 08:39:08 2022 +0200 + + [algorithms.requirements] Add hyphen for non-copied + + commit 63f3e4030497e43f39ff89ec0171f89a11dfc0a7 + Author: Jens Maurer + Date: Fri Jun 17 08:41:53 2022 +0200 + + [alg.equal] Add missing period + + commit 736c755c70be70d5fb75e71f2c212c3c633ddc34 + Author: Casey Carter + Date: Thu Jun 23 14:26:40 2022 -0700 + + [priqueue.overview] Add misssing `>` to deduction guide (#5535) + + commit 3bf6ac52ddd619ae925d32ebb68a90a5bec0c115 + Author: Jens Maurer + Date: Fri Jun 24 15:50:30 2022 +0200 + + [class.prop] Clarify definition of implicit-lifetime class (#5319) + + commit 314fa9e2c16bcdaba33febddf2992b3e26c02212 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Wed Jul 13 01:54:20 2022 +0800 + + [sequence.reqmts] Add ranges namespace qualifier for range concepts (#5563) + + commit 433b7af41ef02b8656c3153ab6ebb1c1c616f5b3 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Wed Jul 13 23:40:21 2022 +0800 + + [range.take.overview] Fix punctuation (#5564) + + commit f6cb84439e8094ec7c67c708d1cc0ddef59262ec + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Jul 26 23:09:38 2022 +0800 + + [ranges.syn] Add \ref for `ref_view` (#5652) + + commit c816ae797e36daa466c287f3eff445aa87d8bfeb + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Jul 29 03:11:43 2022 +0800 + + [istreambuf.iterator.general] Add \ref for proxy (#5669) + + commit d59a4f3392fd1cf87af4ba128518fb4c00cbf77c + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Jul 29 03:13:33 2022 +0800 + + [algorithm.syn,bitset.syn,rand.synopsis,valarray.syn] Add \ref for header (#5666) + + commit 78b91e849b270423ec3296f7f95666078531e032 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sat Jul 30 05:13:40 2022 +0800 + + [range.join.with.overview,range.split.overview] use qualified name in examples (#5683) + + commit e24445344d26e3d9a3ad92b939b8c034daa47eb4 + Author: Thomas Köppe + Date: Sun Aug 14 20:53:03 2022 +0100 + + [mdspan.*] Replace remaining "pointer"s with "data_handle_type". + + These edits are part of LWG Motion 4 (P2604R0) but were accidentally omitted. + + commit 762480c9317759ffd6db76f7fef27744776e081d + Author: Thomas Köppe + Date: Wed Aug 17 11:41:51 2022 +0100 + + [ranges] Remove now-unused exposition-only "tuple-or-pair". + + Also fix one missed replacement of "tuple-or-pair" with "tuple" as + instructed by LWG-Motion 12 (P2165R4, "tuple-like objects"). + + commit b832e2702df41ebe79ddd9d159ac71e68e9b772a + Author: Thomas Köppe + Date: Sun Aug 14 22:26:15 2022 +0100 + + [container.reqmnts] Remove stray `{}` + + commit f09e7c5164d6dbc43e4a160aa4676725a83f488d + Author: Thomas Köppe + Date: Wed Aug 17 15:03:41 2022 +0100 + + [expr.spaceship, fs.path.generic, temp.inst] Use em-dash for parentheticals, not en-dash. + + We are using em-dashes elsewhere already. + + commit 5dd17bf20e46a2964131ec208b6ed31cc659c400 + Author: Thomas Köppe + Date: Wed Aug 17 23:18:35 2022 +0100 + + [ranges] Add missing requirement on itemdecl, and fix spacing + + commit bb1145f751e2de491873aac5a42faf0a6931c218 + Author: Thomas Köppe + Date: Fri Aug 12 12:03:55 2022 +0100 + + [mdspan.{overview,extents.ctor}] Increase reuse of definitions + + commit e97f917d3fd39d7fb2421105d8e45cb73bd24a1e + Author: Eelis van der Weegen + Date: Thu Aug 18 18:42:15 2022 +0200 + + [range.zip.transform.view] Fix typo: mmove_constructible. + + commit f440cfa4e3ebf139b5acec3735e90d4acf5785e6 + Author: Thomas Köppe + Date: Thu Aug 18 15:25:55 2022 +0100 + + [ranges.syn] Add missing "freestanding" comment for as_rvalue. + + commit 999005ab72ca0078b3361979584007dd9d991fac + Author: Yihe Li + Date: Fri Aug 5 08:49:10 2022 +0800 + + [strings.general] Add header to "String classes" row + + commit 1fbf5f8b683802849cfc8bb57fef3f48a61bd242 + Author: Yihe Li + Date: Fri Aug 5 08:49:40 2022 +0800 + + [thread.general] Remove non-existent header + + commit 0d7d1d70641a773f67b08f4de44e53f00e3b352d + Author: Jens Maurer + Date: Fri Jun 24 15:40:43 2022 +0200 + + [temp.inst] Clarify referent of 'declaration' + + commit 99bc532e3c9440defd761985d2329da064b7f9f9 + Author: Jens Maurer + Date: Thu Jun 23 23:17:13 2022 +0200 + + [module.private.frag] Remove misleading example and broaden note + + commit 596137c054407d4d5f2ccf327bd5d3e2a8b4fef5 + Author: A. Jiang + Date: Tue May 17 09:49:27 2022 +0800 + + [mem.poly.allocator.class.general] Clarify polymorphic_allocator etc. + + commit 193cfc17cbb73e7e6c65d1e596ef9c1a035c7811 + Author: Jens Maurer + Date: Fri Nov 5 19:58:41 2021 +0100 + + [diff.dcl] Discuss 'alignas' placement restrictions + + commit 8b2d70502c379b96ddb9d6eb97d5aafcc1d4765c + Author: Jens Maurer + Date: Fri Nov 5 20:00:00 2021 +0100 + + [diff.dcl] Remove 'implicit int' discussion + + C99 has removed implicit int. + + commit f91c425a8fe6f0dd826bd399a5bc82796aec8180 + Author: Jens Maurer + Date: Fri Mar 4 21:20:21 2022 +0100 + + [diff.expr] Remove 'implicit function declaration' discussion + + C99 has removed implicit function declarations. + + commit b208eb4da5a97cf800f2822318fd487f332d82ad + Author: Jonathan Wakely + Date: Fri Feb 22 06:22:04 2019 +0000 + + [meta.trans.other] Use "denotes" in decay, enable_if and conditional + + commit 769e15bd0559a8ff572d2c508f2cce0227229a39 + Author: Jonathan Wakely + Date: Fri Feb 22 07:04:02 2019 +0000 + + [meta.unary.prop.query] Use "is an array type" not "names an array type" + + commit 3d010460fc4159b6f99d430a3cf0eb0ff30d0053 + Author: Jonathan Wakely + Date: Fri Feb 22 07:05:09 2019 +0000 + + [meta.trans.ref] Use "is a referenceable type" and "denotes the type" + + commit 66cb97967adb501ff352b6e69815b4db10e095bf + Author: Jonathan Wakely + Date: Fri Feb 22 07:06:14 2019 +0000 + + [meta.trans.sign] Use "is a ... type" and "denotes the type" + + commit 485192fb3872c1da42d6cc0ff89230ecb7760c9c + Author: Jonathan Wakely + Date: Fri Feb 22 07:06:46 2019 +0000 + + [meta.trans.arr] Use "is a type" not "names a type" + + Also use "denotes" instead of "names" for member typedefs. + + commit e2d032255ad0f346144659ba43d3eb184163c8bb + Author: Jonathan Wakely + Date: Fri Feb 22 07:07:15 2019 +0000 + + [meta.trans.ptr] Use "is a referenceable type" not "names ..." + + commit 2c9482a15375291528e8742dc7972450c9597d96 + Author: Jonathan Wakely + Date: Fri Feb 22 07:09:00 2019 +0000 + + [meta.trans.other] Use "denotes" + + commit c51087e82583b589481f03d4dad2190a569ce857 + Author: Jonathan Wakely + Date: Fri Feb 22 07:16:14 2019 +0000 + + [meta.trans.cv] use "denotes" in specification of member typedefs + + commit 935ec9e8f13d41bc09f8a27a917008ddf2724a29 + Author: Jonathan Wakely + Date: Tue Apr 23 10:33:16 2019 +0100 + + [refwrap.unwrapref] Use "denotes" for member typedef + + commit e412ba9b687e4cdd8ed7546b3ec44122b6baabc5 + Author: Jonathan Wakely + Date: Fri Apr 22 18:20:59 2022 +0100 + + [depr.meta.types] use "denotes" for member typedefs + + commit 887c0330bdd2e4b504854a5c9d34621e5d10a3d2 + Author: Jens Maurer + Date: Tue Nov 27 21:27:28 2018 +0100 + + [cmp.categories] Replace 'operator admits' phrasing. + + commit 1e3e4180ee26e06abe6eeb648537b36baa92c5b7 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Aug 19 01:33:25 2022 +0800 + + [range.as.const.view] Add missing angle bracket (#5745) + + commit d732538953bab8ccdbe4388cfb39b8542a01dc65 + Author: Arthur O'Dwyer + Date: Thu Jul 21 10:09:09 2022 -0400 + + [map.cons,multimap.cons,multiset.cons,set.cons,associative.reqmts.general] "sorted with respect to `comp`" + + https://cplusplus.github.io/LWG/issue3713 + LWG3713 points out that we temporarily lost the term of art + "sorted with respect to `comp`," and brings back a definition + for it. However, several places in the existing draft never + actually used that term of art in the first place. Fix them + up so that they do. + + commit 4db1d62426ef9a9cd8689585d43da38dd3731696 + Author: A. Jiang + Date: Fri Aug 19 01:36:40 2022 +0800 + + [allocator.requirements.general] Use newer style for SimpleAllocator + + commit a458849089b29e3dfc5f9736799c1c6403223f8f + Author: Jens Maurer + Date: Sun Jun 12 16:11:08 2022 +0200 + + [thread.lock.unique.locking] Fix function call expressions + + commit dd4ecf3d19bf8a04899324fc72c690880a328a64 + Author: Jens Maurer + Date: Fri May 13 21:51:13 2022 +0200 + + [stacktrace.basic.nonmem] Add missing \pnum before \recommended + + Also augment check script + + commit fe24762404f5ac7bbd6f139a44dbfa42663ec796 + Author: Barry Revzin + Date: Thu Aug 18 16:03:10 2022 -0500 + + [stmt.pre] List "compound-statement" explicitly as part of a selection statement + + This clarifies the substatements of `if consteval` (which has a compound-statement). + + commit 2940703c7ee125ce8194f668683ff5b0bbd7791b + Author: Jens Maurer + Date: Sun Jan 2 21:46:02 2022 +0100 + + [core] Replace 'enumerated type' with 'enumeration' + + The term "enumerated type" is defined in [enumerated.types] + for use in the standard library, and is not synonymous with + "enumeration type". + + commit a27e5a6ac3a0fc9cb8474b87b92734a923d495c0 + Author: Hubert Tong + Date: Fri Aug 19 10:36:20 2022 -0400 + + [stmt.label, except.pre] Use new wording "control-flow-limited" statement (#5413) + + A new term of art (control-flow-limited statement) is introduced in [stmt.label] + to express the restrictions on control flow into a statement (namely jumping to labels). + Both [stmt.if] and [except.pre] are updated to use the new term. + + This rewords "shall not be used to" avoiding question of actual "use": the "shall not be + used to" phrasing may be taken to refer only in cases where the actual use occurs + or is the primary intent. Instead, the intended restriction can be written in terms + of static properties of the constructs so restricted in the style of [stmt.if]. + + commit 5aa000973bba1ce10ce0f4ca6a3bec61bcea2061 + Author: Jason Merrill + Date: Fri Aug 19 10:47:42 2022 -0400 + + [lex.charset] Add missing hyphens + + In P2071R2 and NameAliases.txt, 0+008E is named SINGLE-SHIFT-2, but it went + into the draft as "single shift-2", losing the hyphen between the words. + + commit 8275c19b3fa9e7cb09f84049ebd6207aceb7ca80 + Author: Thomas Köppe + Date: Fri Aug 19 17:29:40 2022 +0100 + + [range.cartesian.view] Fix definition of cartesian-product-is-common + + The original wording seems to have been a copy-paste error. + + commit 4117a1fc1aeb307d6b15c8aba8a54925fb1b4faf + Author: Mark de Wever + Date: Fri Aug 19 18:37:58 2022 +0200 + + [format.string.escaped] Fix invalid examples + + While implementing new features introduced by P2286R8 Formatting Ranges + I noticed some issues in the examples. These issues are in the paper + too. + + For s3 the alternative would be to adjust the output instead of the + input. + + commit 2d548b2ec835510685cf2fcb175f7645aa798d72 + Author: Thomas Köppe + Date: Fri Aug 19 09:35:25 2022 +0100 + + [dcl.fct.def.default] Elaborate on the difference of two declarations + + This makes it clear that T_1 and T_2 may differ because of the present + rule for the purposes of the blanket statement "other than as allowed + by the preceding rules" futher below. + + commit d2ad0017c5584825fce1cbf741c160e4bd6108b3 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sun Aug 21 01:22:25 2022 +0800 + + [range.chunk.overview,range.slide.overview] Use maths, not code style for N/M (#5500) + + commit 1277923e3ac7a35a3713823b5782b57b86f956ed + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sun Aug 21 01:35:35 2022 +0800 + + [range.chunk] Fix subclause headings (#5516) + + commit 2f228c5cad223a5c8d686d91b054ee3bd2d2a123 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Sun Aug 21 05:01:17 2022 +0800 + + [range.as.rvalue.view] Fix accidentally swapped concepts in template head + + Also fixes the whitespace style around the opening brace. + + commit 22133b42b1a20d542a8f4d18cc425e8c875e567b + Author: Thomas Köppe + Date: Sat Aug 20 22:04:26 2022 +0100 + + [complex.members] Remove stray "template" from constructor + + This peculiar presentation had previously worked in conjuction with + a subclause on "explicit specializations", but since those explicit + specializations have been removed by P1467R9, the template head does + not serve any useful purpose any longer. + + commit fee56834fb55355d617a88fe764f9fb20d92c329 + Author: Thomas Köppe + Date: Sat Aug 20 22:35:28 2022 +0100 + + [expr.prim.lambda.capture] Add cross reference to [basic.scope.lambda] + + Suggested by CD review feedback. + + commit 6f70f82eead9ddc10830aedb99286d0db54725ad + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Aug 22 02:11:57 2022 +0800 + + [range.repeat.view] Fix typo (#5765) + + commit 89df45a30a48f30d2ab367490b47c2c0a87f4aa6 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Aug 22 01:51:41 2022 +0800 + + [ranges.cartesian.iterator] Fix typo + + commit 35aa22acdf080fc5886d715a965aadd36de28c27 + Author: Thomas Köppe + Date: Sun Aug 21 01:55:27 2022 +0100 + + [expr.prim.id.unqual] Fix parameter name in example ("y", not "z") + + The misspelling was a misapplication of the motion paper P2579R0. + + Also harmonize the local use of whitespace. + + commit 2841712fc15f831481d7bd39e084c213596ccfec + Author: Thomas Köppe + Date: Sat Aug 20 23:49:21 2022 +0100 + + [vector.syn, vector.bool] Add subclause structure. + + After the addition of the formatting-related specialization, the + original subclause contained several class template synopses without + any intervening separation. The header synopsis is rearranged to + follow the document order. + + commit 259b8d5d1beeaccf793783679ff4956e84774ea4 + Author: Thomas Köppe + Date: Mon Aug 22 00:03:46 2022 +0100 + + [alg.sorting.general] Make "comp" part of the defined term + + Suggested by CD review feedback. + + commit c2aee77b6413fe8ce09bf816d1e239fa2b93f4a9 + Author: Thomas Köppe + Date: Mon Aug 22 00:14:49 2022 +0100 + + [mdspan.overview] Extend the definition to "size of a MD index space" + + Previously, only "size" was the defined term, but P0009R18 asks for + the entire phrase to be the defined term. + + Suggested by CD review feedback. + + commit ac27094ee2f367faf32a37008f476d57b19fd999 + Author: Thomas Köppe + Date: Mon Aug 22 00:29:15 2022 +0100 + + [mdspan.extents.expo] Add "exposition-only" comments to itemdecls + + Suggested by CD review feedback. + + commit cce4e845272506ad2e0d732d78bce1dcfd02b7c7 + Author: Thomas Köppe + Date: Mon Aug 22 00:34:32 2022 +0100 + + [mdspan.extents.ctor] Consistently use "r" as a maths variable, not code. + + Suggested by CD review feedback. + + commit a284ab6c16f387f95adb85e02ad9c07cf36b08a3 + Author: Thomas Köppe + Date: Mon Aug 22 00:43:14 2022 +0100 + + [mdspan.layout.{reqmts,right.ctor}] Consistently use maths, not code + + Suggested by CD review feedback. + + commit 62d024620d93fc08611ce9e931fef95c9e064d03 + Author: Thomas Köppe + Date: Mon Aug 22 00:52:22 2022 +0100 + + [mdspan.accessor.reqmts] Replace "pointer" with "data_handle_type". + + This edit was part of LWG Motion 4 (P2604R0) but was accidentally omitted. + + commit 9369f4c7f116244193c7c2ed12ecc4a625790776 + Author: Thomas Köppe + Date: Mon Aug 22 00:56:57 2022 +0100 + + [mdspan.layout.stride.expo] Replace "SizeType" with "IndexType". + + This edit was part of LWG Motion 3 (P2599R2) but was accidentally omitted. + + commit fd7c919c681630425a48fd01b4c36c631c910303 + Author: Thomas Köppe + Date: Mon Aug 22 01:01:14 2022 +0100 + + [mdspan.layout.stride.{ctor,obs}] Add cross references to [mdspan.layout.policy.reqmts] + + Suggested by CD review feedback. + + commit d0c287b45c5b7ec1d5cfffed2eeeed2e2682ed3b + Author: Thomas Köppe + Date: Mon Aug 22 09:59:57 2022 +0100 + + [flat.multi*] Fix typo ("mutli" => "multi") + + commit 06cbf011ea876313132b51f3699b23f942f91123 + Author: Thomas Köppe + Date: Mon Aug 22 10:13:01 2022 +0100 + + [containers] Add cross references to "erasure" subclauses + + In associative containers, the comment in the synopsis is augmented + with the name of the class template, since each header contains two + class templates (unique and multi). + + Also fixes some index entry spellings. + + commit 3b1461021cb81fbbccd27494ecd60de7daf958b8 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Aug 22 17:56:54 2022 +0800 + + [range.adaptor.tuple] Fix tuple helper parameter name clash (#5769) + + The code as presented originally was ill-formed. + + commit 90c2cfb1fb8e5cb4781a2d8affdc8856279ca09a + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Aug 22 09:32:17 2022 +0800 + + [range.repeat.iterator] repeat_view::iterator is not a class template + + commit 4762e1b6fa3bcaf4fdc080e2160ab4e9e96f77b6 + Author: A. Jiang + Date: Mon Aug 22 15:32:10 2022 +0800 + + Fix preconditions for start_lifetime_as_array(p, n) + + "n > 0 is true" can't be in "Mandates:", and it's in "Preconditions:" according to P2590R2. + + commit 28f49c965a394c573fa927792f082a182d422029 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Mon Aug 22 19:29:40 2022 +0800 + + [range.as.const.view] Fix order of constraints in class synopsis (#5760) + + The header and the class synopses used different orderings in P2446R0, + and the ordering from the header synopsis is the desired one. + + commit 03d73772246ec6e9fa0becb983be6dc08189d8b1 + Author: Thomas Köppe + Date: Mon Aug 22 12:23:51 2022 +0100 + + [flat.*] Harmonize wording "supports the ... operations but not ..." + + commit 9934675dd673bfa8e073bd3c2187575b47e6ea44 + Author: Thomas Köppe + Date: Mon Aug 22 13:48:45 2022 +0100 + + [flat.set.defn] Fix name of function parameter ("rg", not "range") + + commit faa173c296bfc3547e6f20af63329ac0e1a024be + Author: Thomas Köppe + Date: Mon Aug 22 14:06:39 2022 +0100 + + [flat.multiset.ctor] Add missing parameter name "cont" + + commit 96fce7b5259e1bfe1688cc60df2d6b2ecf3e7cd1 + Author: Thomas Köppe + Date: Mon Aug 22 11:49:41 2022 +0100 + + [flat.*.{syn,erasure}] Change return type of erase_if to member size_type + + All other containers and container adapters use the member size_type, + and the flat maps already did so in the item specification, but not in + the synopsis. + + The current wording follows the approved proposals, but this change + seems like an improvement. + + Suggested by CD review feedback. + + commit 7f11031bf6e41515a8779bdbfe741f4f9bbdfccc + Author: Thomas Köppe + Date: Sat Aug 20 21:14:55 2022 +0100 + + [diff] Uniform style for examples + + For C++ differences, examples are always preceded by the phrase "For + example:", do not use the usual [Example n: ... -- end example] style, + and always appear in the "Effects on original feature" paragraph. + + For differences with C, a different set of styles is used (examples + being part of paragraphs such as "Change" and "Rationale"), and that + subclause remains unchanged by this commit. + + commit d4280f38ddd489aecd8fb0da17a41f577db42e2a + Author: Thomas Köppe + Date: Sat Aug 20 23:11:39 2022 +0100 + + [memory.syn] Add missing "// freestanding" comment to "destroy" + + The comment was supposed to be added by P1642R11, but was accidentally + omitted. + + commit 47b0e73cc1e8d2ea344afedf60e07ec80df118f4 + Author: mordante + Date: Mon Aug 22 17:48:36 2022 +0200 + + [format.string.std] Reorder std-format-spec field descriptions. (#5246) + + Moves the wording describing the zero-padding before the description of + the width; matching the order of the fields in the std-format-spec. + + The original order was introduced in the initial paper P0645R10 "Text Formatting". + Since both fields had one paragraph of description, it wasn't too noticeable. P1868R2 "🦄 width: + clarifying units of width and precision in std::format" expanded the wording of the width. + Now it's not so easy to find the description of the zero-padding field. + + commit 517290b26fa8391d3b77d43ca8c271bb92695db7 + Author: Thomas Köppe + Date: Mon Aug 22 17:06:34 2022 +0100 + + [range.cartesian.view] Further fixing of cartesian-product-is-common + + The first fix in 8275c19b3fa9e7cb09f84049ebd6207aceb7ca80 was + incorrect. Only Const needs to be dropped (which was an error + in the paper), but ignoring Vs... is intentional. + + commit 101e7205882495cec1a944c7f6190b08bd131543 + Author: Thomas Köppe + Date: Mon Aug 22 17:23:46 2022 +0100 + + [ranges] Add missing closing delimiters + + commit 17be256d2431f66842479bf7ab2e92f30fff3060 + Author: Jens Maurer + Date: Sat Jun 18 21:39:06 2022 +0200 + + [alg.partitions] Indicate base of logarithm outside big-oh notation + + commit c6e83c4dba380b235be59b21db6c54bdffcb997d + Author: Jens Maurer + Date: Sat Jun 18 21:39:59 2022 +0200 + + [set.difference] Fix grammar typo + + commit 68e365415c707038f8af6c76f0f6f4cd3a4ce407 + Author: Jens Maurer + Date: Sat Jun 18 21:44:05 2022 +0200 + + [uninitialized.move] Fix typos in parameter names + + commit c3c6761111cff26e0e742e4d14b5d9e0bd28c4aa + Author: Jens Maurer + Date: Sat Jun 18 22:53:51 2022 +0200 + + [rand.adapt.disc] Remove superfluous trailing semicolon + + commit 65c9e5bcb3068a1172a66a7507d26a93adae7981 + Author: Jens Maurer + Date: Sat Jun 18 22:55:17 2022 +0200 + + [rand.adapt.ibits] Remove superfluous trailing semicolon + + commit 6ede23707505a18cdbb558108d635a0b21a1eeb0 + Author: Jens Maurer + Date: Sat Jun 18 22:55:47 2022 +0200 + + [rand.adapt.shuf] Remove superfluous trailing semicolon + + commit 5e44bc70b72b64e03e0d09564b2eaf45938a7752 + Author: Jens Maurer + Date: Sat Jun 18 22:58:11 2022 +0200 + + [valarray.members] Fix bad reference to argument + + commit 43b2bce231b04c1ccf7dc4bfd20e13f29c0e9c6c + Author: Jens Maurer + Date: Sun Jun 19 21:29:54 2022 +0200 + + [time.duration.io] Fix grammar typo + + commit 6e9b678f03a1a4fa8218152596a1952c209d1f27 + Author: Jens Maurer + Date: Sun Jun 19 21:32:40 2022 +0200 + + [time.cal.year.members] Fix erroneous qualified-id + + commit f0ab64a1dcb5bac1249ff67e838a7f899efeb586 + Author: Jens Maurer + Date: Sun Jun 19 21:39:48 2022 +0200 + + [locale.codecvt.general] Remove extra space before template-argument-list + + commit bbb7552af35266accf98ae718912579527ee11b8 + Author: Jens Maurer + Date: Sun Jun 19 21:41:58 2022 +0200 + + [locale.collate.general] Fix grammar typo + + commit 324dfd448ec5b632fc922015414cd206920b5842 + Author: Jens Maurer + Date: Sun Jun 19 21:45:29 2022 +0200 + + [ios.base.storage] Fix grammar typo + + commit fc53c9ede41d4992dc64f556bc32febb28ad0e1e + Author: Jens Maurer + Date: Sun Jun 19 21:45:58 2022 +0200 + + [fpos] Fix typo in exposition-only member + + commit 47273ceb655716f62fc1c9fe00a317b44c221267 + Author: Jens Maurer + Date: Sun Jun 19 21:47:05 2022 +0200 + + [fpos.operations] Fix name of type trait + + commit 04d7e61e9deaf2481d144e2c0a7d2478cff58764 + Author: Jens Maurer + Date: Sun Jun 19 21:49:00 2022 +0200 + + [streambuf.cons] Fix grammar typo + + commit f055ba09397bd479317a92c315e5a074f7c2e474 + Author: Jens Maurer + Date: Sun Apr 17 11:19:04 2022 +0200 + + [atomics.syn] Move namespace-scope memory_order_* variables here + + commit f400d80927fd580f99f5f2d94c3d07eaa47373d0 + Author: Jens Maurer + Date: Sun Apr 17 11:23:54 2022 +0200 + + [ranges.syn] Move namespace-scope declarations for get(subrange) here + + commit e9434db227e8b3113a477dcdd0c6c14ffe2c14b8 + Author: Jonathan Wakely + Date: Mon Aug 22 18:56:41 2022 +0100 + + [tuple.creation] Add missing semi-colon to example + + commit 25bb0a278e8141613f2c813c50a74428e3da7b8b + Author: Jonathan Wakely + Date: Mon Aug 22 18:58:39 2022 +0100 + + [util.smartptr.shared.obs], [util.smartptr.shared.create] use nullptr for null pointer constant + + commit 7a4324c21e4f66af801bc7e7fc78b94119253301 + Author: Jonathan Wakely + Date: Mon Aug 22 21:52:22 2022 +0100 + + [char.traits.require] use nullptr for null pointer constant + + commit b3b64b35ce456a7e54476b9a00185323b68fcd6d + Author: Jonathan Wakely + Date: Mon Aug 22 22:01:22 2022 +0100 + + [unord.req.general] Use "constant" not "const" + + commit a421a3029418651b9734ae786c9b89b72b08b42d + Author: Jonathan Wakely + Date: Mon Aug 22 22:09:00 2022 +0100 + + [unord.multimap.overview] Fix presentation of member types + + As already done in de6b0e70ffe2da0a0f91ce434863202f78c9e029 for unordered_map. + + commit a758844278a818fd8ccbd33a6ca0460b31616d74 + Author: Jonathan Wakely + Date: Mon Aug 22 22:33:04 2022 +0100 + + [range.elements.view] fix class-key for iterator and sentinel + + commit 44b146eda750e453ee3d52587c2accab4be6c74d + Author: Jonathan Wakely + Date: Mon Aug 22 22:35:18 2022 +0100 + + [range.elements.iterator] remove stray semi-colon + + commit 3a51f3e858e14abc0623f8823e0d2c883c27a4e4 + Author: Jonathan Wakely + Date: Mon Aug 22 22:45:30 2022 +0100 + + [complex.ops] use character literal for single character + + commit 678907e6d8af62cab9429b7065be69c36ffa2592 + Author: Jonathan Wakely + Date: Mon Aug 22 22:46:43 2022 +0100 + + [rand.req.dist] fix grammar typo + + commit 698be9d6b09517dc1323ca99fc4bb84ec62fae9e + Author: Jonathan Wakely + Date: Mon Aug 22 22:56:42 2022 +0100 + + [cons.slice], [gslice.cons] remove undeclared/undocumented copy constructor signatures + + commit 1cda1f9d2ac5d8caa81e793ce3f95364aba1fb6b + Author: Jonathan Wakely + Date: Mon Aug 22 23:01:23 2022 +0100 + + [template.mask.array.overview], [template.indirect.array.overview] fix itemdecl typos + + commit f3ddcf79a971f488b3acf0e52ca6ea9689af7fd7 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Aug 23 19:58:08 2022 +0800 + + [ranges.cartesian.iterator] Fix typo "reference_t" => "range_reference_t" (#5777) + + commit 227c3b249f0f52484920400b861717649895e6cc + Author: cor3ntin + Date: Tue Aug 23 14:00:44 2022 +0200 + + [range.adjacent.overview] Use tuple in example, not pair (#5779) + + adjacent_view always yields tuples, but the example was written as if it yielded a std::pair. + + commit c0c0d75402b1dc33f0cba971c898dc2ac7bfaa06 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Aug 23 20:00:49 2022 +0800 + + [range.cartesian.view] Add missing angle brackets for cartesian-is-sized-sentinel + + commit c777f930668fe23ab287ff765463d3b3731696eb + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Aug 23 21:45:23 2022 +0800 + + [range.zip, ranges.cartesian.iterator] Simplify `maybe-const` to `const Views` (#5778) + + The type `maybe-const` only appears after `Const &&` + in these cases, so that only the case where `Const` is `true` matters. + + commit eca39f43798d7a58fdd482232c60b6db428b656f + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Wed Aug 24 01:57:58 2022 +0800 + + [tuple.syn, tuple.like] Fix template head formatting (#5784) + + commit 356fb7ff88b63d956b1109c72c5e3bf424f6ba29 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Wed Aug 24 01:58:17 2022 +0800 + + [algorithm.syn] Fix template head formatting (#5786) + + commit 6ccb959c7a8c10fc5fa7dd469c64f3c992e7e7ee + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Aug 23 20:10:44 2022 +0800 + + [range.zip.overview] Use tuple in example, not pair + + commit 8404284d8b7ac6ff2725a33d5e33410d1ea3b470 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Tue Aug 23 23:10:39 2022 +0800 + + [range.drop.overview, range.take.overview] Fixed unformatted (void)F, decay-copy(E) + + commit 6e2b23594abd64c9ba50934654c68bd174c7ab91 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Wed Aug 24 18:49:21 2022 +0800 + + [format.range.fmtstr] Add ranges namespace qualifier (#5788) + + The range concept is named outside of the `ranges` namespace. + + commit 301f0cdcb547f54b1d39163550a5869a0c6b073f + Author: Thomas Köppe + Date: Thu Aug 25 02:28:09 2022 +0100 + + [coroutine.syn] Move "all freestanding" comment to the top + + commit e38650de03741a87d6c625ce93974946f46f5caa + Author: Thomas Köppe + Date: Thu Aug 25 02:41:49 2022 +0100 + + [tuple.like] Remove extraneous "std::" qualification. + + commit 3da6b0e8798681144b676b3b4180301f8f7c8f2c + Author: Thomas Köppe + Date: Thu Aug 25 10:55:25 2022 +0100 + + [const.iterators.{alias,iterators}] Add "exposition only" comments + + Suggested by CD review feedback. + + commit 5dd0216a477391fbce339e22f169136420472979 + Author: Thomas Köppe + Date: Thu Aug 25 11:12:24 2022 +0100 + + [range.refinements] Fix template argument name ("T", not "R") + + commit 347ded018d09d2a226e3ab42665d1a13b25d489a + Author: Thomas Köppe + Date: Thu Aug 25 11:27:38 2022 +0100 + + [vector.bool.pspc] Reinstate redundant "inline", as per paper + + The "inline" was removed editorially in + 2141dab25c7f6d186d662e0ebe916efcd56843ae, but CD review has requested + we retain it. + + commit 79ab62930d2538e1ef668c6a1b50e8d7027ebedc + Author: Thomas Köppe + Date: Thu Aug 25 11:34:57 2022 +0100 + + [format.string.escaped] Fix typos in "APOSTROPHE" + + commit 426ce8a7ec2232aebaaf76bf2f5e4a69a500cef6 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Thu Aug 25 19:31:57 2022 +0800 + + [ranges] Tweak some examples (#5791) + + Removes redundant `std::` qualifications and uses `views::meow` instead of `meow_view`. + + commit 4ed7fcf6b725207ac307a6d1411ad2aa4ed55c8f + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Aug 26 04:36:08 2022 +0800 + + [containers] Add `std::` for `forward`/`move` (#5793) + + commit aec46d1970a8869db0d178c436545b0e40968425 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Aug 26 04:43:03 2022 +0800 + + [move.sentinel] Remove extraneous "std" qualification in example (#5792) + + commit ed18148b1d514c0aea12d99b1ec3a56d4a834266 + Author: Hewill Kang <67143766+hewillk@users.noreply.github.com> + Date: Fri Aug 26 15:00:12 2022 +0800 + + [util.smartptr.shared.create] Add std:: qualification for forward + + commit eb703517cd6c79f56df12c5dca359121efbef4ee + Author: Thomas Köppe + Date: Fri Aug 26 14:39:39 2022 +0100 + + [range.move.wrap] Fix constraint (move, not copy-constructible) + + This was accidentally omitted from previous changes requested by P2494R2. + + commit 2a600822d08332a8350e3a093212bdc7f8a82e2b + Author: Thomas Köppe + Date: Fri Aug 26 15:06:06 2022 +0100 + + [format.range.fmtdef] Add "exposition only" comments + + commit 9d71b7d3b0aac1f179fc3973b0ff1624b00b07ce + Author: Thomas Köppe + Date: Fri Aug 26 15:26:39 2022 +0100 + + [obj.lifetime] Add cross-reference pointing at basic.types.general + + Suggested by CD review feedback. + + commit 9eb92bf36b19381a534273ad98e296dfeb7a0fc9 + Author: Jens Maurer + Date: Mon Aug 29 22:45:41 2022 +0200 + + [flat.set.modifiers] Remove stray 'return' in Effects clause + + commit 69177109f387d3958ffea237c9b0419e4d2aa49c + Author: Thomas Köppe + Date: Fri Sep 2 23:44:14 2022 +0100 + + [expr.ass] Fix typo, "~" should be "^". + + This was a misapplication of P2327R1 in 0aebf5cacded1b64cf089dbc7a0504fbb9f50aa6. + + commit e6e17d5e136934f113d6e0a8bde4c227459a9d47 + Author: Thomas Köppe + Date: Sat Sep 3 02:10:27 2022 +0100 + + [diff.cpp20.{dcl,expr}] Fix subclause order to match main document + + commit 853747c5d8130880b96a39ab940c343aa7530d71 + Author: Thomas Köppe + Date: Sat Sep 3 15:02:00 2022 +0100 + + [basic.fundamental] Use correct number; "are", not "is". + + commit 07e02a80fe890dcb6e84182a5697046f1bd4c630 + Author: Jens Maurer + Date: Mon Aug 29 22:23:54 2022 +0200 + + [expected.object.assign] Add missing 'Returns: *this' + + commit 06dcf0556631382ecdc420c22c66366168c226b4 + Author: Thomas Köppe + Date: Sun Sep 4 13:01:12 2022 +0100 + + [mdspan.layout.left.overview] Reorder "explicit" and "constexpr" + + The standard ordering is "constexpr explicit", not the other way + round. The paper P0009R18 contains a non-standard style, and other + instances had already been fixed. Only this one seems to have been + missed previously. + + commit e651f145df7c587ea810aca754e680bb27ea8481 + Author: Thomas Köppe + Date: Sun Sep 4 13:08:42 2022 +0100 + + [mdspan.layout.{left,right}.overview] Replace "see below" with condition + + The condition is spelled out in the item descriptions already, and the + class synopses seem to simply have been inconsistent with that in the + incoming paper P0009R18. Since the "see below"s are never referenced + explicitly, we just replace them with the actual conditions, which is + also how the surrounding members are presented. + + commit 1765844a9382e1f3415bbbdcd12eaa09a6b1f827 + Author: Thomas Köppe + Date: Sun Sep 4 13:25:52 2022 +0100 + + [mdspan.layout.stride.expo] Move "otherwise" from trailing to leading + + We have a mild preference for the leading position. + + commit c02512ecf3f15fb0f29dc602eb153bc7dabd643d + Author: Thomas Köppe + Date: Sun Sep 4 13:53:01 2022 +0100 + + [mdspan.layout.stride.obs] Add missing parentheses + + commit 9897c566ec3ecd6f25078a3dd10ce34c17e812e7 + Author: Thomas Köppe + Date: Sun Sep 4 13:54:19 2022 +0100 + + [mdspan.accessor.default.members] Fix typo in "equivalent" + + commit 3b6163d1a3b1f5cc2be49d6ff0eb6b3889b552df + Author: Thomas Köppe + Date: Sun Sep 4 13:58:09 2022 +0100 + + [flat.map.syn] Add missing "namespace std {" + + commit c164add6cdac73cae85649ba2172de43c3d8ed5b + Author: Thomas Köppe + Date: Sun Sep 4 14:02:11 2022 +0100 + + [flat.map.modifiers] Typo: "range" should be "rg" + + commit 1b427b20fecbc95b98d2380e0ddae71b71c1f657 + Author: Thomas Köppe + Date: Sun Sep 4 14:06:53 2022 +0100 + + [flat.{,multi}set.ctor] Add missing "explicit" in itemdecls + + commit 8f153df9c66c33f100ec7a4d7998dfaf6a7aa8da + Author: Thomas Köppe + Date: Thu Nov 26 02:43:37 2020 +0000 + + [basic, except, diff] Rewordings to avoid "might" and "could" diff --git a/papers/wd-index.md b/papers/wd-index.md index 5b3d4dee1e..5d6a4f75a1 100644 --- a/papers/wd-index.md +++ b/papers/wd-index.md @@ -41,3 +41,4 @@ * [N4892](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/n4892.pdf) 2021-06 C++ Working Draft * [N4901](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/n4901.pdf) 2021-10 C++ Working Draft * [N4910](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/n4910.pdf) 2022-03 C++ Working Draft + * [N4910](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/n4917.pdf) 2022-07 C++ Working Draft diff --git a/source/algorithms.tex b/source/algorithms.tex index 4c0f369fac..1a4d627698 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -69,6 +69,11 @@ Throughout this Clause, where the template parameters are not constrained, the names of template parameters are used to express type requirements. \begin{itemize} +\item + If an algorithm's \Fundescx{Effects} element specifies + that a value pointed to by any iterator passed as an argument is modified, + then the type of that argument shall meet + the requirements of a mutable iterator\iref{iterator.requirements}. \item If an algorithm's template parameter is named \tcode{InputIterator}, @@ -86,16 +91,18 @@ \item If an algorithm's template parameter is named \tcode{ForwardIterator}, - \tcode{ForwardIterator1}, or - \tcode{Forward\-Iterator2}, + \tcode{ForwardIterator1}, + \tcode{ForwardItera\-tor2}, or + \tcode{NoThrowForwardIterator}, the template argument shall meet the - \oldconcept{ForwardIterator} requirements\iref{forward.iterators}. + \oldconcept{ForwardIterator} requirements\iref{forward.iterators} + if it is required to be a mutable iterator, or + model \libconcept{forward_iterator}\iref{iterator.concept.forward} otherwise. \item If an algorithm's template parameter is named \tcode{NoThrowForwardIterator}, - the template argument shall meet the - \oldconcept{ForwardIterator} requirements\iref{forward.iterators}, and - is required to have the property that no exceptions are thrown + the template argument + is also required to have the property that no exceptions are thrown from increment, assignment, or comparison of, or indirection through, valid iterators. \item @@ -104,28 +111,23 @@ \tcode{Bidirectional\-Iterator1}, or \tcode{BidirectionalIterator2}, the template argument shall meet the - \oldconcept{BidirectionalIterator} requirements\iref{bidirectional.iterators}. + \oldconcept{BidirectionalIterator} requirements\iref{bidirectional.iterators} + if it is required to be a mutable iterator, or model + \libconcept{bidirectional_iterator}\iref{iterator.concept.bidir} otherwise. \item If an algorithm's template parameter is named \tcode{RandomAccessIterator}, \tcode{Random\-AccessIterator1}, or \tcode{RandomAccessIterator2}, the template argument shall meet the - \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators}. + \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators} + if it is required to be a mutable iterator, or model + \libconcept{random_access_iterator}\iref{iterator.concept.random.access} otherwise. \end{itemize} - -\pnum -If an algorithm's \effects element specifies -that a value pointed to by any iterator passed as an argument is modified, -then that algorithm has an additional type requirement: -The type of that argument shall meet -the requirements of a mutable iterator\iref{iterator.requirements}. \begin{note} -This requirement does not affect arguments that are named -\tcode{OutputIterator}, \tcode{OutputIterator1}, or \tcode{OutputIterator2}, -because output iterators must always be mutable, nor -does it affect arguments that are constrained, -for which mutability requirements are expressed explicitly. +These requirements do not affect iterator arguments that are constrained, +for which iterator category and mutability requirements +are expressed explicitly. \end{note} \pnum @@ -163,10 +165,10 @@ \pnum When not otherwise constrained, the \tcode{BinaryPredicate} parameter is used -whenever an algorithm expects a function object that when applied +whenever an algorithm expects a function object that, when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type \tcode{T} -when \tcode{T} is part of the signature +when \tcode{T} is part of the signature, returns a value testable as \tcode{true}. In other words, if an algorithm takes \tcode{BinaryPredicate binary_pred} as its argument and @@ -208,7 +210,7 @@ Unless otherwise specified, algorithms that take function objects as arguments can copy those function objects freely. If object identity is important, -a wrapper class that points to a noncopied implementation object +a wrapper class that points to a non-copied implementation object such as \tcode{reference_wrapper}\iref{refwrap}, or some equivalent solution, can be used. \end{note} @@ -616,7 +618,7 @@ \indexheader{algorithm}% \begin{codeblock} -#include +#include // see \ref{initializer.list.syn} namespace std { namespace ranges { @@ -642,6 +644,9 @@ template struct in_found_result; + template + struct in_value_result; + template struct out_value_result; } @@ -695,6 +700,29 @@ constexpr bool none_of(R&& r, Pred pred, Proj proj = {}); } + // \ref{alg.contains}, contains + namespace ranges { + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + 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> + requires + @\libconcept{indirect_binary_predicate}@, Proj>, const T*> + constexpr bool contains(R&& r, const T& value, Proj proj = {}); + + template<@\libconcept{forward_iterator}@ I1, @\libconcept{sentinel_for}@ S1, + @\libconcept{forward_iterator}@ I2, @\libconcept{sentinel_for}@ S2, + class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> + requires @\libconcept{indirectly_comparable}@ + constexpr bool contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2, + Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); + template<@\libconcept{forward_range}@ R1, @\libconcept{forward_range}@ R2, + class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> + requires @\libconcept{indirectly_comparable}@, iterator_t, Pred, Proj1, Proj2> + constexpr bool contains_subrange(R1&& r1, R2&& r2, + Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); + } + // \ref{alg.foreach}, for each template constexpr Function for_each(InputIterator first, InputIterator last, Function f); @@ -780,6 +808,29 @@ find_if_not(R&& r, Pred pred, Proj proj = {}); } + // \ref{alg.find.last}, find last + namespace ranges { + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + requires @\libconcept{indirect_binary_predicate}@, const T*> + constexpr subrange find_last(I first, S last, const T& value, Proj proj = {}); + template<@\libconcept{forward_range}@ R, class T, class Proj = identity> + requires + @\libconcept{indirect_binary_predicate}@, Proj>, const T*> + constexpr borrowed_subrange_t find_last(R&& r, const T& value, Proj proj = {}); + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + @\libconcept{indirect_unary_predicate}@> Pred> + constexpr subrange find_last_if(I first, S last, Pred pred, Proj proj = {}); + template<@\libconcept{forward_range}@ R, class Proj = identity, + @\libconcept{indirect_unary_predicate}@, Proj>> Pred> + constexpr borrowed_subrange_t find_last_if(R&& r, Pred pred, Proj proj = {}); + template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + @\libconcept{indirect_unary_predicate}@> Pred> + constexpr subrange find_last_if_not(I first, S last, Pred pred, Proj proj = {}); + template<@\libconcept{forward_range}@ R, class Proj = identity, + @\libconcept{indirect_unary_predicate}@, Proj>> Pred> + constexpr borrowed_subrange_t find_last_if_not(R&& r, Pred pred, Proj proj = {}); + } + // \ref{alg.find.end}, find end template constexpr ForwardIterator1 @@ -1169,6 +1220,91 @@ @\libconcept{indirectly_comparable}@, iterator_t, Pred, Proj1, Proj2> constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); + + // \ref{alg.fold}, fold + template + class @\exposid{flipped}@ { // \expos + F @\exposid{f}@; // \expos + + public: + template requires @\libconcept{invocable}@ + invoke_result_t operator()(T&&, U&&); + }; + + template + concept @\defexposconcept{indirectly-binary-left-foldable-impl}@ = // \expos + @\libconcept{movable}@ && @\libconcept{movable}@ && + @\libconcept{convertible_to}@ && @\libconcept{invocable}@> && + @\libconcept{assignable_from}@>>; + + template + concept @\defexposconcept{indirectly-binary-left-foldable}@ = // \expos + @\libconcept{copy_constructible}@ && @\libconcept{indirectly_readable}@ && + @\libconcept{invocable}@> && + @\libconcept{convertible_to}@>, + decay_t>>> && + @\exposconcept{indirectly-binary-left-foldable-impl}@>>>; + + template + 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, + @\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> + constexpr auto fold_left(R&& r, T init, F f); + + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, + @\exposconcept{indirectly-binary-left-foldable}@, I> F> + requires @\libconcept{constructible_from}@, iter_reference_t> + constexpr auto fold_left_first(I first, S last, F f); + + template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@, iterator_t> F> + 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, + @\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, + @\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); + + template<@\libconcept{bidirectional_range}@ R, + @\exposconcept{indirectly-binary-right-foldable}@, iterator_t> F> + requires @\libconcept{constructible_from}@, range_reference_t> + constexpr auto fold_right_last(R&& r, F f); + + template + using fold_left_with_iter_result = in_value_result; + template + using fold_left_first_with_iter_result = in_value_result; + + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class 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> + constexpr @\seebelow@ fold_left_with_iter(R&& r, T init, F f); + + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, + @\exposconcept{indirectly-binary-left-foldable}@, I> F> + requires @\libconcept{constructible_from}@, iter_reference_t> + constexpr @\seebelow@ fold_left_first_with_iter(I first, S last, F f); + + template<@\libconcept{input_range}@ R, + @\exposconcept{indirectly-binary-left-foldable}@, iterator_t> F> + requires @\libconcept{constructible_from}@, range_reference_t> + constexpr @\seebelow@ fold_left_first_with_iter(R&& r, F f); } // \ref{alg.modifying.operations}, mutating sequence operations @@ -1318,7 +1454,7 @@ requires @\libconcept{indirectly_swappable}@ constexpr swap_ranges_result swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); - template<@\libconcept{input_range}@ R1, input_range R2> + template<@\libconcept{input_range}@ R1, @\libconcept{input_range}@ R2> requires @\libconcept{indirectly_swappable}@, iterator_t> constexpr swap_ranges_result, borrowed_iterator_t> swap_ranges(R1&& r1, R2&& r2); @@ -3058,6 +3194,24 @@ } }; + template + struct in_value_result { + [[no_unique_address]] I in; + [[no_unique_address]] T value; + + template + requires @\libconcept{convertible_to}@ && @\libconcept{convertible_to}@ + constexpr operator in_value_result() const & { + return {in, value}; + } + + template + requires @\libconcept{convertible_to}@ && @\libconcept{convertible_to}@ + constexpr operator in_value_result() && { + return {std::move(in), std::move(value)}; + } + }; + template struct out_value_result { [[no_unique_address]] O out; @@ -3200,6 +3354,45 @@ At most \tcode{last - first} applications of the predicate and any projection. \end{itemdescr} +\rSec2[alg.contains]{Contains} + +\indexlibraryglobal{contains}% +\begin{itemdecl} +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + 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> + requires @\libconcept{indirect_binary_predicate}@, Proj>, const T*> + constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{ranges::find(std::move(first), last, value, proj) != last}. +\end{itemdescr} + +\indexlibraryglobal{contains_subrange}% +\begin{itemdecl} +template<@\libconcept{forward_iterator}@ I1, @\libconcept{sentinel_for}@ S1, + @\libconcept{forward_iterator}@ I2, @\libconcept{sentinel_for}@ S2, + class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> + requires @\libconcept{indirectly_comparable}@ + constexpr bool ranges::contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2, + Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); +template<@\libconcept{forward_range}@ R1, @\libconcept{forward_range}@ R2, + class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> + requires @\libconcept{indirectly_comparable}@, iterator_t, Pred, Proj1, Proj2> + constexpr bool ranges::contains_subrange(R1&& r1, R2&& r2, Pred pred = {}, + Proj1 proj1 = {}, Proj2 proj2 = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{first2 == last2 || !ranges::search(first1, last1, first2, last2, pred, proj1, proj2).empty()}. +\end{itemdescr} + \rSec2[alg.foreach]{For each} \indexlibraryglobal{for_each}% @@ -3514,6 +3707,55 @@ of the corresponding predicate and any projection. \end{itemdescr} +\rSec2[alg.find.last]{Find last} + +\indexlibraryglobal{find_last}% +\begin{itemdecl} +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class T, class Proj = identity> + 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> + 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, + @\libconcept{indirect_unary_predicate}@> Pred> + constexpr subrange ranges::find_last_if(I first, S last, Pred pred, Proj proj = {}); +template<@\libconcept{forward_range}@ R, class Proj = identity, + @\libconcept{indirect_unary_predicate}@, Proj>> Pred> + constexpr borrowed_subrange_t ranges::find_last_if(R&& r, Pred pred, Proj proj = {}); +template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, + @\libconcept{indirect_unary_predicate}@> Pred> + constexpr subrange ranges::find_last_if_not(I first, S last, Pred pred, Proj proj = {}); +template<@\libconcept{forward_range}@ R, class Proj = identity, + @\libconcept{indirect_unary_predicate}@, Proj>> Pred> + constexpr borrowed_subrange_t ranges::find_last_if_not(R&& r, Pred pred, Proj proj = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $E$ be: +\begin{itemize} +\item +\tcode{bool(invoke(proj, *i) == value)} for \tcode{ranges::find_last}; +\item +\tcode{bool(invoke(pred, invoke(proj, *i)))} for \tcode{ranges::find_last_if}; +\item +\tcode{bool(!invoke(pred, invoke(proj, *i)))} for \tcode{ranges::find_last_if_not}. +\end{itemize} + +\pnum +\returns +Let \tcode{i} be the last iterator in the range \range{first}{last} +for which $E$ is \tcode{true}. +Returns \tcode{\{i, last\}}, or +\tcode{\{last, last\}} if no such iterator is found. + +\pnum +\complexity +At most \tcode{last - first} applications of +the corresponding predicate and projection. +\end{itemdescr} + \rSec2[alg.find.end]{Find end} \indexlibraryglobal{find_end}% @@ -3979,7 +4221,7 @@ \returns If \tcode{last1 - first1 != last2 - first2}, return \tcode{false}. Otherwise return \tcode{true} -if $E$ holds for every iterator \tcode{i} in the range \range{first1}{last1} +if $E$ holds for every iterator \tcode{i} in the range \range{first1}{last1}. Otherwise, returns \tcode{false}. \pnum @@ -4384,6 +4626,170 @@ \end{codeblock} \end{itemdescr} +\rSec2[alg.fold]{Fold} + +\indexlibraryglobal{fold_left}% +\begin{itemdecl} +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class 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> + constexpr auto ranges::fold_left(R&& r, T init, F f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{codeblock} +ranges::fold_left_with_iter(std::move(first), last, std::move(init), f).value +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{fold_left_first}% +\begin{itemdecl} +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, + @\exposconcept{indirectly-binary-left-foldable}@, I> F> + requires @\libconcept{constructible_from}@, iter_reference_t> + constexpr auto ranges::fold_left_first(I first, S last, F f); +template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@, iterator_t> F> + requires @\libconcept{constructible_from}@, range_reference_t> + constexpr auto ranges::fold_left_first(R&& r, F f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{codeblock} +ranges::fold_left_first_with_iter(std::move(first), last, f).value +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{fold_right}% +\begin{itemdecl} +template<@\libconcept{bidirectional_iterator}@ I, @\libconcept{sentinel_for}@ S, class 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, + @\exposconcept{indirectly-binary-right-foldable}@> F> + constexpr auto ranges::fold_right(R&& r, T init, F f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +using U = decay_t, T>>; +if (first == last) + return U(std::move(init)); +I tail = ranges::next(first, last); +U accum = invoke(f, *--tail, std::move(init)); +while (first != tail) + accum = invoke(f, *--tail, std::move(accum)); +return accum; +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{fold_right_last}% +\begin{itemdecl} +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 ranges::fold_right_last(I first, S last, F f); +template<@\libconcept{bidirectional_range}@ R, + @\exposconcept{indirectly-binary-right-foldable}@, iterator_t> F> + requires @\libconcept{constructible_from}@, range_reference_t> + constexpr auto ranges::fold_right_last(R&& r, F f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{U} be +\tcode{decltype(ranges::fold_right(first, last, iter_value_t(*first), f))}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (first == last) + return optional(); +I tail = ranges::prev(ranges::next(first, std::move(last))); +return optional(in_place, + ranges::fold_right(std::move(first), tail, iter_value_t(*tail), std::move(f))); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{fold_left_with_iter}% +\begin{itemdecl} +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, class 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> + constexpr @\seebelow@ ranges::fold_left_with_iter(R&& r, T init, F f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{U} be \tcode{decay_t>>}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (first == last) + return {std::move(first), U(std::move(init))}; +U accum = invoke(f, std::move(init), *first); +for (++first; first != last; ++first) + accum = invoke(f, std::move(accum), *first); +return {std::move(first), std::move(accum)}; +\end{codeblock} + +\pnum +\remarks +The return type is +\tcode{fold_left_with_iter_result} for the first overload and +\tcode{fold_left_with_iter_result, U>} +for the second overload. +\end{itemdescr} + +\indexlibraryglobal{fold_left_first_with_iter}% +\begin{itemdecl} +template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, + @\exposconcept{indirectly-binary-left-foldable}@, I> F> + requires @\libconcept{constructible_from}@, iter_reference_t> + constexpr @\seebelow@ ranges::fold_left_first_with_iter(I first, S last, F f); +template<@\libconcept{input_range}@ R, @\exposconcept{indirectly-binary-left-foldable}@, iterator_t> F> + requires @\libconcept{constructible_from}@, range_reference_t> + constexpr @\seebelow@ ranges::fold_left_first_with_iter(R&& r, F f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{U} be +\begin{codeblock} +decltype(ranges::fold_left(std::move(first), last, iter_value_t(*first), f)) +\end{codeblock} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (first == last) + return {std::move(first), optional()}; +optional init(in_place, *first); +for (++first; first != last; ++first) + *init = invoke(f, std::move(*init), *first); +return {std::move(first), std::move(init)}; +\end{codeblock} + +\pnum +\remarks +The return type is +\tcode{fold_left_first_with_iter_result>} +for the first overload and +\tcode{fold_left_first_with_iter_result, optional>} +for the second overload. +\end{itemdescr} + \rSec1[alg.modifying.operations]{Mutating sequence operations} \rSec2[alg.copy]{Copy} @@ -4615,7 +5021,7 @@ into the range \range{result - $N$}{result} starting from \tcode{last - 1} and proceeding to \tcode{first}. \begin{footnote} -\tcode{copy_backward} can be used instead of copy +\tcode{copy_backward} can be used instead of \tcode{copy} when \tcode{last} is in the range \range{result - $N$}{result}. \end{footnote} For each positive integer $n \le N$, @@ -4768,7 +5174,7 @@ into the range \range{result - $N$}{result} starting from \tcode{last - 1} and proceeding to \tcode{first}. \begin{footnote} -\tcode{move_backward} can be used instead of move +\tcode{move_backward} can be used instead of \tcode{move} when \tcode{last} is in the range \range{result - $N$}{result}. \end{footnote} For each positive integer $n \le N$, @@ -4808,7 +5214,7 @@ requires @\libconcept{indirectly_swappable}@ constexpr ranges::swap_ranges_result ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); -template<@\libconcept{input_range}@ R1, input_range R2> +template<@\libconcept{input_range}@ R1, @\libconcept{input_range}@ R2> requires @\libconcept{indirectly_swappable}@, iterator_t> constexpr ranges::swap_ranges_result, borrowed_iterator_t> ranges::swap_ranges(R1&& r1, R2&& r2); @@ -5207,7 +5613,6 @@ ForwardIterator fill_n(ExecutionPolicy&& exec, ForwardIterator first, Size n, const T& value); - template O, @\libconcept{sentinel_for}@ S> constexpr O ranges::fill(O first, S last, const T& value); template R> @@ -5629,8 +6034,8 @@ \item For the overloads with no \tcode{ExecutionPolicy}, let \tcode{T} be the value type of \tcode{InputIterator}. - If \tcode{InputIterator} meets - the \oldconcept{ForwardIterator} requirements, + If \tcode{InputIterator} models + \libconcept{forward_iterator}\iref{iterator.concept.forward}, then there are no additional requirements for \tcode{T}. Otherwise, if \tcode{OutputIterator} meets the \oldconcept{ForwardIterator} requirements and @@ -5935,8 +6340,8 @@ \item \tcode{SampleIterator} meets the \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators} - unless \tcode{Pop\-ulat\-ion\-Iter\-ator} meets - the \oldconcept{ForwardIterator} requirements\iref{forward.iterators}. + unless \tcode{Pop\-ulat\-ion\-Iter\-ator} + models \libconcept{forward_iterator}\iref{iterator.concept.forward}. \item \tcode{remove_reference_t} meets the requirements of a uniform random bit generator type\iref{rand.req.urng}. @@ -5965,8 +6370,8 @@ \begin{itemize} \item For the overload in namespace \tcode{std}, - stable if and only if \tcode{PopulationIterator} meets - the \oldconcept{For\-wardIterator} requirements. + stable if and only if \tcode{PopulationIterator} + models \libconcept{forward_iterator}. For the first overload in namespace \tcode{ranges}, stable if and only if \tcode{I} models \libconcept{forward_iterator}. \item @@ -6206,6 +6611,7 @@ \end{note} \pnum +\indexdefn{sequence!sorted!with respect to a comparator and projection}% A sequence is \term{sorted with respect to a \tcode{comp} and \tcode{proj}} for a comparator and projection \tcode{comp} and \tcode{proj} if for every iterator \tcode{i} pointing to the sequence and @@ -6217,6 +6623,13 @@ \end{codeblock} is \tcode{false}. +\pnum +\indexdefn{sequence!sorted!with respect to a comparator}% +A sequence is \term{sorted with respect to a comparator \tcode{comp}} +for a comparator \tcode{comp} +if it is sorted with respect to +\tcode{comp} and \tcode{identity\{\}} (the identity projection). + \pnum A sequence \range{start}{finish} is \term{partitioned with respect to an expression} \tcode{f(e)} @@ -7147,13 +7560,12 @@ \item \tcode{\{i, last\}} for the overloads in namespace \tcode{ranges}. \end{itemize} - \pnum \complexity Let $N$ = \tcode{last - first}: \begin{itemize} \item - For the overloads with no \tcode{ExecutionPolicy}, at most $N \log N$ swaps, + For the overloads with no \tcode{ExecutionPolicy}, at most $N \log_2 N$ swaps, but only \bigoh{N} swaps if there is enough extra memory. Exactly $N$ applications of the predicate and projection. \item @@ -7818,7 +8230,7 @@ \range{first2}{last2} contains $n$ elements that are equivalent to them, the last $\max(m - n, 0)$ elements from \range{first1}{last1} -is copied to the output range, in order. +are copied to the output range, in order. \end{itemdescr} \rSec3[set.symmetric.difference]{\tcode{set_symmetric_difference}} @@ -8643,11 +9055,11 @@ template<@\libconcept{forward_iterator}@ I, @\libconcept{sentinel_for}@ S, class Proj = identity, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> - constexpr ranges::minmax_result + constexpr ranges::minmax_element_result ranges::minmax_element(I first, S last, Comp comp = {}, Proj proj = {}); template<@\libconcept{forward_range}@ R, class Proj = identity, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> - constexpr ranges::minmax_result> + constexpr ranges::minmax_element_result> ranges::minmax_element(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -10119,7 +10531,7 @@ For all overloads, in the ranges \crange{first}{last} and \crange{result}{result + (last - first)}, \tcode{binary_op} neither modifies elements - nor invalidate iterators or subranges. + nor invalidates iterators or subranges. \begin{footnote} The use of fully closed ranges is intentional. \end{footnote} @@ -10383,7 +10795,7 @@ \begin{itemdescr} \pnum -A type \tcode{I} models \tcode{\placeholder{nothrow-input-iterator}} only if +A type \tcode{I} models \exposconcept{nothrow-input-iterator} only if no exceptions are thrown from increment, copy construction, move construction, copy assignment, move assignment, @@ -10403,7 +10815,7 @@ \begin{itemdescr} \pnum -Types \tcode{S} and \tcode{I} model \tcode{\placeholder{nothrow-sentinel-for}} +Types \tcode{S} and \tcode{I} model \exposconcept{nothrow-sentinel-for} only if no exceptions are thrown from copy construction, move construction, copy assignment, move assignment, or comparisons between valid values of type \tcode{I} and \tcode{S}. @@ -10418,14 +10830,14 @@ \begin{itemdecl} template concept @\defexposconcept{nothrow-input-range}@ = // \expos - range && - @\placeholder{nothrow-input-iterator}@> && - @\placeholder{nothrow-sentinel-for}@, iterator_t>; + @\libconcept{range}@ && + @\exposconcept{nothrow-input-iterator}@> && + @\exposconcept{nothrow-sentinel-for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum -A type \tcode{R} models \tcode{\placeholder{nothrow-input-range}} only if +A type \tcode{R} models \exposconcept{nothrow-input-range} only if no exceptions are thrown from calls to \tcode{ranges::begin} and \tcode{ranges::end} on an object of type \tcode{R}. \end{itemdescr} @@ -10433,9 +10845,9 @@ \begin{itemdecl} template concept @\defexposconcept{nothrow-forward-iterator}@ = // \expos - @\placeholder{nothrow-input-iterator}@ && + @\exposconcept{nothrow-input-iterator}@ && @\libconcept{forward_iterator}@ && - @\placeholder{nothrow-sentinel-for}@; + @\exposconcept{nothrow-sentinel-for}@; \end{itemdecl} \begin{itemdescr} @@ -10449,8 +10861,8 @@ \begin{itemdecl} template concept @\defexposconcept{nothrow-forward-range}@ = // \expos - @\placeholder{nothrow-input-range}@ && - @\placeholder{nothrow-forward-iterator}@>; + @\exposconcept{nothrow-input-range}@ && + @\exposconcept{nothrow-forward-iterator}@>; \end{itemdecl} \rSec2[uninitialized.construct.default]{\tcode{uninitialized_default_construct}} @@ -10475,10 +10887,10 @@ \indexlibraryglobal{uninitialized_default_construct}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-forward-iterator}@ I, @\placeholder{nothrow-sentinel-for}@ S> + template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> I uninitialized_default_construct(I first, S last); - template<@\placeholdernc{nothrow-forward-range}@ R> + template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> borrowed_iterator_t uninitialized_default_construct(R&& r); } @@ -10516,7 +10928,7 @@ \indexlibraryglobal{uninitialized_default_construct_n}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-forward-iterator}@ I> + template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> I uninitialized_default_construct_n(I first, iter_difference_t n); } @@ -10554,10 +10966,10 @@ \indexlibraryglobal{uninitialized_value_construct}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-forward-iterator}@ I, @\placeholder{nothrow-sentinel-for}@ S> + template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> I uninitialized_value_construct(I first, S last); - template<@\placeholdernc{nothrow-forward-range}@ R> + template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> borrowed_iterator_t uninitialized_value_construct(R&& r); } @@ -10595,7 +11007,7 @@ \indexlibraryglobal{uninitialized_value_construct_n}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-forward-iterator}@ I> + template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> I uninitialized_value_construct_n(I first, iter_difference_t n); } @@ -10643,11 +11055,11 @@ \begin{itemdecl} namespace ranges { template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, - @\placeholdernc{nothrow-forward-iterator}@ O, @\placeholder{nothrow-sentinel-for}@ S2> + @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_reference_t> uninitialized_copy_result uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); - template<@\libconcept{input_range}@ IR, @\placeholdernc{nothrow-forward-range}@ OR> + template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_reference_t> uninitialized_copy_result, borrowed_iterator_t> uninitialized_copy(IR&& in_range, OR&& out_range); @@ -10698,7 +11110,7 @@ \indexlibraryglobal{uninitialized_copy_n}% \begin{itemdecl} namespace ranges { - template<@\libconcept{input_iterator}@ I, @\placeholdernc{nothrow-forward-iterator}@ O, @\placeholder{nothrow-sentinel-for}@ S> + 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 uninitialized_copy_n(I ifirst, iter_difference_t n, O ofirst, S olast); @@ -10750,11 +11162,11 @@ \begin{itemdecl} namespace ranges { template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, - @\placeholdernc{nothrow-forward-iterator}@ O, @\placeholder{nothrow-sentinel-for}@ S2> + @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> uninitialized_move_result uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); - template<@\libconcept{input_range}@ IR, @\placeholdernc{nothrow-forward-range}@ OR> + template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_rvalue_reference_t> uninitialized_move_result, borrowed_iterator_t> uninitialized_move(IR&& in_range, OR&& out_range); @@ -10778,7 +11190,7 @@ \pnum \begin{note} -If an exception is thrown, some objects in the range \range{first}{last} are +If an exception is thrown, some objects in the range \range{ifirst}{ilast} are left in a valid, but unspecified state. \end{note} \end{itemdescr} @@ -10809,7 +11221,7 @@ \indexlibraryglobal{uninitialized_move_n}% \begin{itemdecl} namespace ranges { - template<@\libconcept{input_iterator}@ I, @\placeholdernc{nothrow-forward-iterator}@ O, @\placeholder{nothrow-sentinel-for}@ S> + 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 uninitialized_move_n(I ifirst, iter_difference_t n, O ofirst, S olast); @@ -10833,7 +11245,7 @@ \pnum \begin{note} If an exception is thrown, some objects in the range -\countedrange{first}{n} +\countedrange{ifirst}{n} are left in a valid but unspecified state. \end{note} \end{itemdescr} @@ -10860,10 +11272,10 @@ \indexlibraryglobal{uninitialized_fill}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-forward-iterator}@ I, @\placeholder{nothrow-sentinel-for}@ S, class T> + 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); - template<@\placeholdernc{nothrow-forward-range}@ R, class T> + template<@\exposconcept{nothrow-forward-range}@ R, class T> requires @\libconcept{constructible_from}@, const T&> borrowed_iterator_t uninitialized_fill(R&& r, const T& x); } @@ -10901,7 +11313,7 @@ \indexlibraryglobal{uninitialized_fill_n}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-forward-iterator}@ I, class T> + 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); } @@ -10985,10 +11397,10 @@ \indexlibraryglobal{destroy}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-input-iterator}@ I, @\placeholder{nothrow-sentinel-for}@ S> + template<@\exposconcept{nothrow-input-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{destructible}@> constexpr I destroy(I first, S last) noexcept; - template<@\placeholdernc{nothrow-input-range}@ R> + template<@\exposconcept{nothrow-input-range}@ R> requires @\libconcept{destructible}@> constexpr borrowed_iterator_t destroy(R&& r) noexcept; } @@ -11025,7 +11437,7 @@ \indexlibraryglobal{destroy_n}% \begin{itemdecl} namespace ranges { - template<@\placeholdernc{nothrow-input-iterator}@ I> + template<@\exposconcept{nothrow-input-iterator}@ I> requires @\libconcept{destructible}@> constexpr I destroy_n(I first, iter_difference_t n) noexcept; } diff --git a/source/back.tex b/source/back.tex index 0314b1007c..dda5569dc8 100644 --- a/source/back.tex +++ b/source/back.tex @@ -13,8 +13,10 @@ \chapter{Bibliography} \doccite{Information technology --- Language independent arithmetic --- Part 1: Integer and floating point arithmetic} \item - ISO/IEC/IEEE 60559:2011, \doccite{Information technology --- - Microprocessor Systems --- Floating-Point arithmetic} + 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 %%% Format for the following entry is based on that specified at @@ -29,6 +31,11 @@ \chapter{Bibliography} Edited by Mark Davis. Revision 33; issued for Unicode 13.0.0. 2020-02-13 [viewed 2021-06-08]. Available from: \url{https://www.unicode.org/reports/tr31/tr31-33.html} +\item + The Unicode Standard Version 14.0, + \doccite{Core Specification}. + Unicode Consortium, ISBN 978-1-936213-29-0, copyright \copyright 2021 Unicode, Inc. + Available from: \url{https://www.unicode.org/versions/Unicode14.0.0/UnicodeStandard-14.0.pdf} \item IANA Time Zone Database. Available from: \url{https://www.iana.org/time-zones} diff --git a/source/basic.tex b/source/basic.tex index ab94c86677..f32e82975f 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -1286,6 +1286,12 @@ its scope extends to the end of the \grammarterm{deduction-guide}. \end{itemize} +\rSec2[basic.scope.lambda]{Lambda scope} + +A \grammarterm{lambda-expression} \tcode{E} introduces a \defnadj{lambda}{scope} +that starts immediately after the \grammarterm{lambda-introducer} of \tcode{E} +and extends to the end of the \grammarterm{compound-statement} of \tcode{E}. + \rSec2[basic.scope.namespace]{Namespace scope} \pnum @@ -1564,7 +1570,7 @@ The result of the search is the declaration set of $S(N,T)$. If it is an invalid set, the program is ill-formed. If it differs from the result of a search in $T$ for $N$ -from immediately after the \grammarterm{class-specifier} of $T$, +in a complete-class context\iref{class.mem} of $T$, the program is ill-formed, no diagnostic required. \begin{example} \begin{codeblock} @@ -2864,7 +2870,7 @@ or defines a constexpr variable initialized to a TU-local value (defined below). \begin{note} An inline function template can be an exposure even though -explicit specializations of it might be usable in other translation units. +certain explicit specializations of it would be usable in other translation units. \end{note} \pnum @@ -2959,7 +2965,7 @@ } void adl(double); -inline void h(auto x) { adl(x); } // OK, but a specialization might be an exposure +inline void h(auto x) { adl(x); } // OK, but certain specializations are exposures \end{codeblocktu} \begin{codeblocktu}{Translation unit \#2} module A; @@ -3049,7 +3055,7 @@ :0, d:8; struct {int ee:8;} e; -} +}; \end{codeblock} contains four separate memory locations: The member \tcode{a} and bit-fields \tcode{d} and \tcode{e.ee} are each separate memory locations, and can be @@ -3328,7 +3334,7 @@ returns a pointer to a suitable created object. \begin{note} Some functions in the \Cpp{} standard library implicitly create objects% -\iref{allocator.traits.members,c.malloc,cstring.syn,bit.cast}. +\iref{obj.lifetime,allocator.traits.members,c.malloc,cstring.syn,bit.cast}. \end{note} \indextext{object model|)} @@ -3829,7 +3835,9 @@ \pnum The library provides default definitions for the global allocation and deallocation functions. Some global allocation and deallocation -functions are replaceable\iref{new.delete}. A \Cpp{} program shall +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 @@ -3868,12 +3876,14 @@ or any other names that the library uses to declare these names. Thus, a \grammarterm{new-expression}, \grammarterm{delete-expression}, or function call that refers to one of -these functions without importing or including the header \libheaderref{new} is -well-formed. However, referring to \tcode{std} +these functions without importing or including the header \libheaderref{new} +or importing a \Cpp{} library module\iref{std.modules} +is well-formed. However, referring to \tcode{std} or \tcode{std::size_t} or \tcode{std::align_val_t} -is ill-formed unless the name has been declared -by importing or including the appropriate header. +is ill-formed unless +a standard library declaration\iref{cstddef.syn,new.syn,std.modules} +of that name precedes\iref{basic.lookup.general} the use of that name. \end{note} Allocation and/or deallocation functions may also be declared and defined for any @@ -4921,9 +4931,6 @@ Type \keyword{wchar_t} is a distinct type that has an \impldef{underlying type of \tcode{wchar_t}} signed or unsigned integer type as its underlying type. -The values of type \keyword{wchar_t} can represent -distinct codes for all members of the largest extended character set -specified among the supported locales\iref{locale}. \pnum \indextext{\idxcode{char8_t}|see{type, \tcode{char8_t}}}% @@ -4993,15 +5000,23 @@ The types \keyword{float}, \keyword{double}, and \tcode{\keyword{long} \keyword{double}}, and cv-qualified versions\iref{basic.type.qualifier} thereof, +are collectively termed +\defnx{standard floating-point types}{type!floating-point!standard}. +An implementation may also provide additional types +that represent floating-point values and define them (and cv-qualified versions thereof) to be +\defnx{extended floating-point types}{type!floating-point!extended}. +The standard and extended floating-point types are collectively termed \defnx{floating-point types}{type!floating-point}. -The value -representation of floating-point types is \impldef{value representation of -floating-point types}. -\indextext{floating-point type!implementation-defined}% \begin{note} -This document imposes no requirements on the accuracy of -floating-point operations; see also~\ref{support.limits}. +Any additional implementation-specific types representing floating-point values +that are not defined by the implementation to be extended floating-point types +are not considered to be floating-point types, and +this document imposes no requirements on them or +their interactions with floating-point types. \end{note} +Except as specified in \ref{basic.extended.fp}, +the object and value representations and accuracy of operations +of floating-point types are \impldef{representation of floating-point types}. \pnum Integral and floating-point types are collectively @@ -5047,6 +5062,90 @@ same value representation, they are nevertheless different types. \end{note} +\rSec2[basic.extended.fp]{Optional extended floating-point types} + +\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, +then the \grammarterm{typedef-name} \tcode{std::float16_t} +is defined 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}. + +\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, +then the \grammarterm{typedef-name} \tcode{std::float32_t} +is defined 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, +then the \grammarterm{typedef-name} \tcode{std::float64_t} +is defined 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, +then the \grammarterm{typedef-name} \tcode{std::float128_t} +is defined 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 +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, +the macro \mname{STDCPP_BFLOAT16_T} is defined, and +the floating-point literal suffixes \tcode{bf16} and \tcode{BF16} are supported. + +\pnum +\begin{note} +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 mantissa, +so the storage used for the mantissa is $p-1$ bits. +ISO/IEC/IEEE 60559 does not assign a name for a type +having the parameters specified for \tcode{std::bfloat16_t}. +\end{note} +\begin{floattable} +{Properties of named extended floating-point types}{basic.extended.fp}{llllll} +\topline +\lhdr{Parameter} & \chdr{\tcode{float16_t}} & \chdr{\tcode{float32_t}} & +\chdr{\tcode{float64_t}} & \chdr{\tcode{float128_t}} & +\rhdr{\tcode{bfloat16_t}} \\ +\capsep +ISO/IEC/IEEE 60559 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 \\ +$w$, exponent field width in bits & 5 & 8 & 11 & 15 & 8 \\ +\end{floattable} + +\pnum +\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 +should be chosen to increase compatibility and interoperability +with the interchange types +\tcode{_Float16}, \tcode{_Float32}, \tcode{_Float64}, and \tcode{_Float128} +defined in ISO/IEC TS 18661-3 and with future versions of the C standard. + \rSec2[basic.compound]{Compound types} \pnum @@ -5082,9 +5181,8 @@ different types at different times, \ref{class.union}; \item -\defnx{enumerations}{\idxcode{enum}}, which comprise a set of named constant values. -Each distinct enumeration constitutes a different -\defnadj{enumerated}{type}, \ref{dcl.enum}; +\defnx{enumerations}{\idxcode{enum}}, +which comprise a set of named constant values, \ref{dcl.enum}; \item \indextext{member pointer to|see{pointer to member}}% @@ -5210,6 +5308,16 @@ even though they have the same address. \end{note} +\pnum +A byte of storage \placeholder{b} +is \defnx{reachable through}{storage!reachable through a pointer value} +a pointer value that points to an object \placeholder{x} +if there is an object \placeholder{y}, +pointer-interconvertible with \placeholder{x}, +such that \placeholder{b} is within the storage occupied by +\placeholder{y}, or the immediately-enclosing array object +if \placeholder{y} is an array element. + \pnum \indextext{pointer|seealso{\tcode{void*}}}% \indextext{\idxcode{void*}!type}% @@ -5335,7 +5443,7 @@ has the top-level cv-qualifier \keyword{volatile}. \end{example} -\rSec2[conv.rank]{Integer conversion rank}% +\rSec2[conv.rank]{Conversion ranks}% \indextext{conversion!integer rank} \pnum @@ -5392,6 +5500,57 @@ conversions\iref{expr.arith.conv}. \end{note} +\pnum +Every floating-point type has a \defnadj{floating-point}{conversion rank} +defined as follows: +\begin{itemize} +\item +The rank of a floating point type \tcode{T} is greater than +the rank of any floating-point type +whose set of values is a proper subset of the set of values of \tcode{T}. +\item +The rank of \tcode{\keyword{long} \keyword{double}} is greater than +the rank of \keyword{double}, +which is greater than the rank of \keyword{float}. +\item +Two extended floating-point types with the same set of values have equal ranks. +\item +An extended floating-point type with the same set of values as +exactly one cv-unqualified standard floating-point type +has a rank equal to the rank of that standard floating-point type. +\item +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}. +\end{itemize} +\begin{note} +The conversion ranks of floating-point types \tcode{T1} and \tcode{T2} +are unordered if the set of values of \tcode{T1} is +neither a subset nor a superset of the set of values of \tcode{T2}. +This can happen when one type has both a larger range and a lower precision +than the other. +\end{note} + +\pnum +Floating-point types that have equal floating-point conversion ranks +are ordered by floating-point conversion subrank. +The subrank forms a total order among types with equal ranks. +The types +\tcode{std::float16_t}, +\tcode{std::float32_t}, +\tcode{std::float64_t}, and +\tcode{std::float128_t}\iref{stdfloat.syn} +have a greater conversion subrank than any standard floating-point type +with equal conversion rank. +Otherwise, the conversion subrank order is +\impldef{floating-point conversion subrank}. + +\pnum +\begin{note} +The floating-point conversion rank and subrank are used in +the definition of the usual arithmetic conversions\iref{expr.arith.conv}. +\end{note} + \rSec1[basic.exec]{Program execution} \rSec2[intro.execution]{Sequential execution} @@ -5805,8 +5964,8 @@ $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}) +$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}) @@ -6207,7 +6366,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 executions (if any) +This is required 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} @@ -6382,12 +6541,19 @@ The function \tcode{main} shall not be a coroutine\iref{dcl.fct.def.coroutine}. The \tcode{main} function shall not be declared with a \grammarterm{linkage-specification}\iref{dcl.link}. -A program -that declares a variable \tcode{main} that belongs to the global scope, or -that declares a function \tcode{main} that belongs to the global scope and +A program that declares +\begin{itemize} +\item +a variable \tcode{main} that belongs to the global scope, or +\item +a function \tcode{main} that belongs to the global scope and is attached to a named module, or -that declares an entity named \tcode{main} +\item +a function template \tcode{main} that belongs to the global scope, or +\item +an entity named \tcode{main} with C language linkage (in any namespace) +\end{itemize} is ill-formed. The name \tcode{main} is not otherwise reserved. diff --git a/source/classes.tex b/source/classes.tex index fa73256323..18b57e45fa 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -302,10 +302,14 @@ \end{note} \pnum -A class \tcode{S} is an \defnadj{implicit-lifetime}{class} -if it is an aggregate or -has at least one trivial eligible constructor and +A class \tcode{S} is an \defnadj{implicit-lifetime}{class} if +\begin{itemize} +\item +it is an aggregate or +\item +it has at least one trivial eligible constructor and a trivial, non-deleted destructor. +\end{itemize} \rSec1[class.name]{Class names} \indextext{definition!class name as type}% @@ -766,7 +770,7 @@ \item every member template of class \tcode{T}; \item every enumerator of every member of class \tcode{T} that is an -unscoped enumerated type; and +unscoped enumeration type; and \item every member of every anonymous union that is a member of class \tcode{T}. @@ -927,12 +931,6 @@ its class or a class derived from its class, or a member thereof, as described below. -\pnum -\indextext{member function!call undefined}% -If a non-static member function of a class \tcode{X} is called for an -object that is not of type \tcode{X}, or of a type derived from -\tcode{X}, the behavior is undefined. - \pnum When an \grammarterm{id-expression}\iref{expr.prim.id} that is not part of a class member access syntax\iref{expr.ref} and not used to form a @@ -1094,13 +1092,6 @@ and, if the class is not abstract\iref{class.abstract}, its virtual base classes are called its \term{potentially constructed subobjects}. -\pnum -A defaulted special member function is -\indextext{member function!constexpr-compatible}% -\defnx{constexpr-compatible}{constexpr-compatible!defaulted special member function} -if the corresponding implicitly-declared special member function -would be a constexpr function. - \rSec2[class.ctor]{Constructors}% \rSec3[class.ctor.general]{General}% @@ -1316,7 +1307,7 @@ If that user-written default constructor would be ill-formed, the program is ill-formed. If that user-written default constructor would satisfy the requirements -of a constexpr constructor\iref{dcl.constexpr}, the implicitly-defined +of a constexpr function\iref{dcl.constexpr}, the implicitly-defined default constructor is \keyword{constexpr}. Before the defaulted default constructor for a class is implicitly defined, @@ -1544,7 +1535,7 @@ A defaulted copy/\brk{}move constructor for a class \tcode{X} is defined as deleted\iref{dcl.fct.def.delete} if \tcode{X} has: \begin{itemize} -\item a potentially constructed subobject type +\item a potentially constructed subobject of type \tcode{M} (or array thereof) that cannot be copied/moved because overload resolution\iref{over.match}, as applied to find \tcode{M}'s @@ -1613,7 +1604,7 @@ its odr-use\iref{term.odr.use,class.temporary}. \end{note} If the implicitly-defined constructor would satisfy the requirements of a -constexpr constructor\iref{dcl.constexpr}, the implicitly-defined +constexpr function\iref{dcl.constexpr}, the implicitly-defined constructor is \keyword{constexpr}. \pnum @@ -1680,7 +1671,7 @@ \indextext{operator!move assignment|see{assignment operator, move}}% A user-declared \term{copy} assignment operator \tcode{X::operator=} is a non-static non-template member function of class \tcode{X} with exactly one -parameter of type \tcode{X}, \tcode{X\&}, \tcode{const X\&}, +non-object parameter of type \tcode{X}, \tcode{X\&}, \tcode{const X\&}, \tcode{volatile X\&}, or \tcode{const volatile X\&}. \begin{footnote} Because @@ -1765,7 +1756,7 @@ \pnum A user-declared move assignment operator \tcode{X::operator=} is a non-static non-template member function of class \tcode{X} with exactly -one parameter of type \tcode{X\&\&}, \tcode{const X\&\&}, \tcode{volatile X\&\&}, or +one non-object parameter of type \tcode{X\&\&}, \tcode{const X\&\&}, \tcode{volatile X\&\&}, or \tcode{const volatile X\&\&}. \begin{note} An overloaded assignment operator must be @@ -1913,20 +1904,7 @@ to assign to an object of its class type), when it is needed for constant evaluation\iref{expr.const}, or when it is explicitly defaulted after its first declaration. -The implicitly-defined copy/move assignment operator is \keyword{constexpr} if -\begin{itemize} -\item -\tcode{X} is a literal type, and - -\item -the assignment operator selected to copy/move each direct base class subobject -is a constexpr function, and - -\item -for each non-static data member of \tcode{X} that is of class type (or array -thereof), the assignment operator selected to copy/move that member is a -constexpr function. -\end{itemize} +The implicitly-defined copy/move assignment operator is \keyword{constexpr}. \pnum Before the defaulted copy/move assignment operator for a class is @@ -2134,7 +2112,7 @@ \pnum A defaulted destructor is a constexpr destructor -if it satisfies the requirements for a constexpr destructor\iref{dcl.constexpr}. +if it satisfies the requirements for a constexpr function\iref{dcl.constexpr}. \pnum A destructor @@ -4482,12 +4460,6 @@ \end{codeblock} \end{example} -\pnum -\begin{note} -The effect of access control on the order of allocation -of data members is specified in~\ref{expr.rel}. -\end{note} - \pnum When a member is redeclared within its class definition, the access specified at its redeclaration shall @@ -5345,7 +5317,7 @@ is called for the initialization of \tcode{v[1]}, \tcode{complex::complex()} -is called for the initialization +is called for the initialization of \tcode{v[2]}, \tcode{v[4]}, and @@ -5844,7 +5816,7 @@ \pnum \begin{note} -\ref{class.cdtor} describes the result of virtual function calls, +\ref{class.cdtor} describes the results of virtual function calls, \tcode{typeid} and \keyword{dynamic_cast}s @@ -6358,45 +6330,6 @@ move construction from the object with automatic storage duration to \tcode{t2} that is elided. \end{example} -\pnum -An \defnadj{implicitly movable}{entity} is -a variable of automatic storage duration -that is either a non-volatile object or -an rvalue reference to a non-volatile object type. -In the following copy-initialization contexts, -a move operation is first considered before attempting a copy operation: -\begin{itemize} -\item If the \grammarterm{expression} in a \tcode{return}\iref{stmt.return} or -\keyword{co_return}\iref{stmt.return.coroutine} statement -is a (possibly parenthesized) \grammarterm{id-expression} -that names an implicitly movable entity declared in the body -or \grammarterm{parameter-declaration-clause} of the innermost enclosing -function or \grammarterm{lambda-expression}, or - -\item if the operand of a \grammarterm{throw-expression}\iref{expr.throw} -is a (possibly parenthesized) \grammarterm{id-expression} -that names an implicitly movable entity -that belongs to a scope that does not contain the \grammarterm{compound-statement} -of the innermost \grammarterm{try-block} or \grammarterm{function-try-block} -(if any) -whose \grammarterm{compound-statement} or \grammarterm{ctor-initializer} -contains the \grammarterm{throw-expression}, -\end{itemize} -overload resolution to select the constructor -for the copy or the \tcode{return_value} overload to call -is first performed as if the expression or operand were an rvalue. -If the first overload resolution fails or was not performed, -overload resolution is performed again, -considering the expression or operand as an lvalue. -\begin{note} -This two-stage overload resolution is performed regardless -of whether copy elision will occur. It determines the constructor -or the \tcode{return_value} overload to be called if -elision is not performed, and the selected constructor -or \tcode{return_value} overload must be accessible even if -the call is elided. -\end{note} - \pnum \begin{example} \begin{codeblock} @@ -6423,9 +6356,29 @@ Weird(Weird&); }; -Weird g() { - Weird w; - return w; // OK, first overload resolution fails, second overload resolution selects \tcode{Weird(Weird\&)} +Weird g(bool b) { + static Weird w1; + Weird w2; + if (b) + return w1; // OK, uses \tcode{Weird(Weird\&)} + else + return w2; // error: \tcode{w2} in this context is an xvalue +} + +int& h(bool b, int i) { + static int s; + if (b) + return s; // OK + else + return i; // error: \tcode{i} is an xvalue +} + +decltype(auto) h2(Thing t) { + return t; // OK, \tcode{t} is an xvalue and \tcode{h2}'s return type is \tcode{Thing} +} + +decltype(auto) h3(Thing t) { + return (t); // OK, \tcode{(t)} is an xvalue and \tcode{h3}'s return type is \tcode{Thing\&\&} } \end{codeblock} \end{example} @@ -6465,15 +6418,14 @@ that is \begin{itemize} \item -a non-static const non-volatile member of \tcode{C} having -one parameter of type \tcode{const C\&} and either -no \grammarterm{ref-qualifier} or -the \grammarterm{ref-qualifier} \tcode{\&}, or +a non-static member or friend of \tcode{C} and \item -a friend of \tcode{C} having either +either has two parameters of type \tcode{const C\&} or -two parameters of type \tcode{C}. +two parameters of type \tcode{C}, +where the implicit object parameter (if any) is considered to be +the first parameter. \end{itemize} A comparison operator function for class \tcode{C} that is defaulted on its first declaration and @@ -6512,35 +6464,6 @@ \tcode{a @ b} is a valid expression. \end{itemize} -\pnum -A defaulted comparison function is -\indextext{operator!comparison!constexpr-compatible}% -\defnx{constexpr-compatible}{constexpr-compatible!defaulted comparison operator} -if it -satisfies the requirements for a constexpr function\iref{dcl.constexpr} and -no overload resolution -performed when determining whether to delete the function -results in a usable candidate that is a non-constexpr function. -\begin{note} -This includes the overload resolutions performed: - -\begin{itemize} -\item -for an \tcode{operator<=>} whose return type is not \keyword{auto}, -when determining whether a synthesized three-way comparison is defined, - -\item -for an \tcode{operator<=>} whose return type is \keyword{auto} or -for an \tcode{operator==}, -for a comparison between an element of the expanded list of -subobjects and itself, or - -\item -for a secondary comparison operator \tcode{@}, -for the expression \tcode{x @ y}. -\end{itemize} -\end{note} - \pnum If the \grammarterm{member-specification} does not explicitly declare diff --git a/source/compatibility.tex b/source/compatibility.tex index 6070af42ea..21cd9c51eb 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -34,14 +34,27 @@ Concatenation of \grammarterm{string-literal}s with different \grammarterm{encoding-prefix}es is now ill-formed. -\begin{example} +For 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} +\diffref{expr.prim.id.unqual} +\change +Change move-eligible \grammarterm{id-expression}s from lvalues to xvalues. +\rationale +Simplify the rules for implicit move. +\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{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} + \diffref{expr.sub} \change Change the meaning of comma in subscript expressions. @@ -49,12 +62,62 @@ Enable repurposing a deprecated syntax to support multidimensional indexing. \effect Valid \CppXX{} code that uses a comma expression within a -subscript expression may fail to compile. For example: +subscript expression may fail to compile. +For 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} +\rSec2[diff.cpp20.dcl]{\ref{dcl.dcl}: declarations} + +\diffref{dcl.init.string} +\change +UTF-8 string literals may initialize arrays of \keyword{char} or +\tcode{\keyword{unsigned} \keyword{char}}. +\rationale +Compatibility with previously written code that conformed to previous versions of this document. +\effect +Arrays of \keyword{char} or \tcode{\keyword{unsigned} \keyword{char}} +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{codeblock} +struct A { + char8_t s[10]; +}; +struct B { + char s[10]; +}; + +void f(A); +void f(B); + +int main() { + f({u8""}); // ambiguous +} +\end{codeblock} + +\rSec2[diff.cpp20.temp]{\ref{temp}: templates} + +\diffref{temp.deduct.type} +\change +Deducing template arguments from exception specifications. +\rationale +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{codeblock} +template struct A { }; +template void f(void (*)(A) noexcept(B)); +void g(A) noexcept; +void h() { + f(g); // ill-formed; previously well-formed +} +\end{codeblock} + \rSec2[diff.cpp20.library]{\ref{library}: library introduction} \diffref{headers} @@ -71,6 +134,34 @@ Valid \CppXX{} code that \tcode{\#include}{s} headers with these names may be invalid in this revision of \Cpp{}. +\rSec2[diff.cpp20.concepts]{\ref{concepts}: concepts library} + +\diffref{cmp.concept,concept.equalitycomparable,concept.totallyordered} +\change +Replace \tcode{common_reference_with} in \tcode{three_way_comparable_with}, +\tcode{equality_comparable_with}, and \tcode{totally_ordered_with} +with an exposition-only concept. +\rationale +Allow uncopyable, but movable, types to model these concepts. +\effect +Valid \CppXX{} code relying on subsumption +with \tcode{common_reference_with} +may fail to compile in this revision of \Cpp{}. +For example: +\begin{codeblock} +template + requires @\libconcept{equality_comparable_with}@ +bool attempted_equals(const T&, const U& u); // previously selected overload + +template + requires @\libconcept{common_reference_with}@&, const remove_reference_t&> +bool attempted_equals(const T& t, const U& u); // ambiguous overload; previously + // rejected by partial ordering +bool test(shared_ptr p) { + return attempted_equals(p, nullptr); // ill-formed; previously well-formed +} +\end{codeblock} + \rSec2[diff.cpp20.utilities]{\ref{utilities}: general utilities library} \diffref{format} @@ -102,7 +193,8 @@ that are not copyable. \effect Valid \CppXX{} code that passes bit fields to formatting functions -may become ill-formed. For example: +may become ill-formed. +For example: \begin{codeblock} struct tiny { int bit: 1; @@ -112,6 +204,29 @@ std::format("{}", t.bit); // ill-formed, previously returned \tcode{"0"} \end{codeblock} +\rSec2[diff.cpp20.strings]{\ref{strings}: strings library} + +\diffref{string.classes} +\change +Additional rvalue overload for the \tcode{substr} member function and +the corresponding constructor. +\rationale +Improve efficiency of operations on rvalues. +\effect +Valid \CppXX{} code that created a substring +by calling \tcode{substr} (or the corresponding constructor) +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{codeblock} +std::string s1 = "some long string that forces allocation", s2 = s1; +std::move(s1).substr(10, 5); +assert(s1 == s2); // unspecified, previously guaranteed to be \tcode{true} +std::string s3(std::move(s2), 10, 5); +assert(s1 == s2); // unspecified, previously guaranteed to be \tcode{true} +\end{codeblock} + \rSec2[diff.cpp20.containers]{\ref{containers}: containers library} \diffref{associative.reqmts,unord.req} @@ -157,7 +272,7 @@ \tcode{module} or \tcode{import} may be interpreted differently in this revision of \Cpp{}. -\begin{example} +For example: \begin{codeblock} class module {}; module m1; // was variable declaration; now \grammarterm{module-declaration} @@ -167,7 +282,6 @@ import j1; // was variable declaration; now \grammarterm{module-import-declaration} ::import j2; // variable declaration \end{codeblock} -\end{example} \diffref{lex.header} \change @@ -178,13 +292,12 @@ When the identifier \tcode{import} is followed by a \tcode{<} character, a \grammarterm{header-name} token may be formed. -\begin{example} +For example: \begin{codeblock} template class import {}; import f(); // ill-formed; previously well-formed ::import g(); // OK \end{codeblock} -\end{example} \diffref{lex.key} \change @@ -231,7 +344,8 @@ \effect 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{}: +may be ill-formed or have different semantics in this revision of \Cpp{}. +For example: \begin{codeblock} namespace N { struct X {}; @@ -254,6 +368,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{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 @@ -284,7 +399,7 @@ \effect Valid ISO \CppXVII{} code may be ill-formed or have undefined behavior in this revision of \Cpp{}. -\begin{example} +For example: \begin{codeblock} int f() { int a = 123; @@ -293,7 +408,6 @@ return a; // undefined behavior; previously returned 123 } \end{codeblock} -\end{example} \diffref{intro.races} \change @@ -332,6 +446,7 @@ Necessary for implementability. \effect Valid \CppXVII{} code may be ill-formed in this revision of \Cpp{}. +For example: \begin{codeblock} typedef struct { void f() {} // ill-formed; previously well-formed @@ -347,6 +462,7 @@ \effect Valid \CppXVII{} code may be ill-formed in this revision of \Cpp{}, with no diagnostic required. +For example: \begin{codeblock} // Translation unit 1 int f(int a = 42); @@ -369,6 +485,7 @@ a type with a user-declared constructor may be ill-formed or have different semantics in this revision of \Cpp{}. +For example: \begin{codeblock} struct A { // not an aggregate; previously an aggregate A() = delete; @@ -410,7 +527,8 @@ Catches bugs. \effect Valid \CppXVII{} code may fail to compile -in this revision of \Cpp{}. For example: +in this revision of \Cpp{}. +For example: \begin{codeblock} bool y[] = { "bc" }; // ill-formed; previously well-formed \end{codeblock} @@ -429,7 +547,8 @@ Necessary for new functionality. \effect Valid \CppXVII{} code may fail to compile -in this revision of \Cpp{}. For example: +in this revision of \Cpp{}. +For example: \begin{codeblock} struct S { explicit (S)(const S&); // ill-formed; previously well-formed @@ -446,7 +565,8 @@ Remove potentially error-prone option for redundancy. \effect Valid \CppXVII{} code may fail to compile -in this revision of \Cpp{}. For example: +in this revision of \Cpp{}. +For example: \begin{codeblock} template struct A { @@ -511,11 +631,12 @@ Improve consistency of equality with three-way comparison and make it easier to write the full complement of equality operations. \effect -Equality and inequality expressions between two objects of different types, -where one is convertible to the other, -could invoke a different operator. -Equality and inequality expressions between two objects of the same type -could become ambiguous. +For certain pairs of types where one is convertible to the other, +equality or inequality expressions between an object of one type +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{codeblock} struct A { operator int() const; @@ -552,6 +673,7 @@ Previously valid code that uses a function name as the left operand of a \tcode{<} operator would become ill-formed. +For example: \begin{codeblock} struct A {}; bool operator<(void (*fp)(), A); @@ -690,7 +812,8 @@ \rationale Increase safety via preventing buffer overflow at compile time. \effect -Valid \CppXVII{} code may fail to compile in this revision of \Cpp{}: +Valid \CppXVII{} code may fail to compile in this revision of \Cpp{}. +For example: \begin{codeblock} auto p = new char[100]; char q[100]; @@ -708,6 +831,7 @@ 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{codeblock} std::cout << u8"text"; // previously called \tcode{operator<<(const char*)} and printed a string; // now ill-formed @@ -727,6 +851,7 @@ 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{codeblock} std::cout << u"text"; // previously formatted the string as a pointer value; // now ill-formed @@ -743,6 +868,7 @@ 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{codeblock} std::filesystem::path p; std::string s1 = p.u8string(); // ill-formed; previously well-formed @@ -795,9 +921,9 @@ \change Remove \tcode{raw_storage_iterator}. \rationale -The iterator encouraged use of algorithms that might throw exceptions, but did -not return the number of elements successfully constructed that might need to -be destroyed in order to avoid leaks. +The iterator encouraged use of potentially-throwing algorithms, but did +not return the number of elements successfully constructed, +as would be necessary to destroy them. \effect A valid \CppXVII{} program that uses this iterator class may fail to compile. @@ -832,8 +958,8 @@ The traits had unreliable or awkward interfaces. The \tcode{is_literal_type} trait provided no way to detect which subset of constructors and member functions of a type were declared \keyword{constexpr}. The \tcode{result_of} -trait had a surprising syntax that could not report the result of a regular -function type. It has been superseded by the \tcode{invoke_result} trait. +trait had a surprising syntax that did not directly support function types. +It has been superseded by the \tcode{invoke_result} trait. \effect A valid \CppXVII{} program that relies on the \tcode{is_literal_type} or \tcode{result_of} type traits, on the \tcode{is_literal_type_v} variable template, @@ -862,8 +988,8 @@ 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 physical source file characters -to translation character set} mapping from physical source file characters to +string literal, as part of the \impldef{mapping input source file characters +to translation character set} mapping from input source file characters to the translation character set. \diffref{lex.ppnumber} @@ -893,8 +1019,6 @@ \effect A valid \CppXIV{} expression utilizing the increment operator on a \tcode{bool} lvalue is ill-formed in this revision of \Cpp{}. -Note that this might occur when the lvalue has a type given by a template -parameter. \diffref{expr.new,expr.delete} \change @@ -931,7 +1055,8 @@ More intuitive deduction behavior. \effect Valid \CppXIV{} code may fail to compile or may change meaning -in this revision of \Cpp{}. For example: +in this revision of \Cpp{}. +For 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 @@ -991,6 +1116,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{codeblock} struct A { template A(T, typename T::type = 0); @@ -1129,7 +1255,7 @@ will execute differently when called with a non-const string's \tcode{.data()} member in this revision of \Cpp{}. - +For example: \begin{codeblock} int f(char *) = delete; int f(const char *); @@ -1147,7 +1273,8 @@ \effect 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{}: +may fail to compile in this revision of \Cpp{}. +For example: \begin{codeblock} #include @@ -1221,8 +1348,8 @@ revision of \Cpp{}. For example, the following code is valid both in \CppXI{} and in 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{}: - +separators in this revision of \Cpp{}. +For example: \begin{codeblock} #define M(x, ...) __VA_ARGS__ int x[2] = { M(1'2,3'4, 5) }; @@ -1244,7 +1371,6 @@ void* operator new(std::size_t, std::size_t); void operator delete(void*, std::size_t) noexcept; \end{codeblock} - In this revision of \Cpp{}, however, the declaration of \tcode{operator delete} might match a predefined usual (non-placement) \tcode{operator delete}\iref{basic.stc.dynamic}. If so, the @@ -1264,8 +1390,8 @@ lvalue-to-rvalue conversion, were considered gratuitous and surprising. \effect Valid \CppXI{} code that relies on the conversions may behave differently -in this revision of \Cpp{}: - +in this revision of \Cpp{}. +For example: \begin{codeblock} struct S { int x = 1; @@ -1277,14 +1403,11 @@ return s.x; } \end{codeblock} - In \CppXI{}, \tcode{f(true)} returns \tcode{1}. In this revision of \Cpp{}, it returns \tcode{2}. - \begin{codeblock} sizeof(true ? "" : throw 0) \end{codeblock} - In \CppXI{}, the expression yields \tcode{sizeof(const char*)}. In this revision of \Cpp{}, it yields \tcode{sizeof(const char[1])}. @@ -1299,15 +1422,16 @@ the object. \effect Valid \CppXI{} code may fail to compile in this revision of \Cpp{}. -For example, the following code is valid in \CppXI{} -but invalid in this revision of \Cpp{} because it declares the same member -function twice with different return types: +For example: \begin{codeblock} struct S { constexpr const int &f(); int &f(); }; \end{codeblock} +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. \diffref{dcl.init.aggr} \change @@ -1377,7 +1501,8 @@ this revision of \Cpp{}. Specifically, macros named \tcode{R}, \tcode{u8}, \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: +part of the \grammarterm{string-literal}. +For example: \begin{codeblock} #define u8 "abc" const char* s = u8"def"; // Previously \tcode{"abcdef"}, now \tcode{"def"} @@ -1496,13 +1621,14 @@ \rationale Catches bugs. \effect -Valid \CppIII{} code may fail to compile in this revision of \Cpp{}. For -example, the following code is valid in \CppIII{} but invalid in this -revision of \Cpp{} because \tcode{double} to \tcode{int} is a narrowing -conversion: +Valid \CppIII{} code may fail to compile in this revision of \Cpp{}. +For 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. \rSec2[diff.cpp03.class]{\ref{class}: classes} @@ -1550,15 +1676,15 @@ 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, the following code is valid in \CppIII{} because ``\tcode{>>}'' -is a right-shift operator, but invalid in this revision of \Cpp{} because -``\tcode{>>}'' closes two templates. - +For example: \begin{codeblock} template struct X { }; template struct Y { }; X< Y< 1 >> 2 > > x; \end{codeblock} +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. \diffref{temp.dep.candidate} \change @@ -1566,7 +1692,7 @@ \rationale Overly constrained, simplify overload resolution rules. \effect -A valid \CppIII{} program could get a different result than in this +A valid \CppIII{} program can get a different result in this revision of \Cpp{}. \rSec2[diff.cpp03.library]{\ref{library}: library introduction} @@ -1885,7 +2011,8 @@ \effect 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: +with this revision of \Cpp{}. +For example: \begin{codeblock} #include @@ -1932,26 +2059,21 @@ 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. For example: \begin{codeblock} int function( int i ); int function( char c ); function( 'x' ); \end{codeblock} - It is preferable that this call match the second version of function rather than the first. \effect Change to semantics of well-defined feature. ISO C programs which depend on - \begin{codeblock} sizeof('x') == sizeof(int) \end{codeblock} - will not work the same as \Cpp{} programs. \difficulty Simple. @@ -2001,7 +2123,6 @@ Change to semantics of well-defined feature. \difficulty Syntactic transformation. The fix is to add a cast: - \begin{codeblock} char* p = "abc"; // valid in C, invalid in \Cpp{} void f(char*) { @@ -2010,7 +2131,6 @@ f((char*)"def"); // OK, cast added } \end{codeblock} - \howwide Programs that have a legitimate reason to treat string literal objects as potentially modifiable memory are probably rare. @@ -2037,7 +2157,6 @@ static struct X b = { 0, &a }; static struct X a = { 1, &b }; \end{codeblock} - \rationale This avoids having different initialization rules for fundamental types and user-defined types. @@ -2132,7 +2251,6 @@ \diffref{conv.ptr} \change Converting \tcode{\keyword{void}*} to a pointer-to-object type requires casting. - \begin{codeblock} char a[10]; void* b=a; @@ -2164,21 +2282,6 @@ Some ISO C translators will give a warning if the cast is not used. -\diffref{expr.call} -\change -Implicit declaration of functions is not allowed. -\rationale -The type-safe nature of \Cpp{}. -\effect -Deletion of semantically well-defined feature. -Note: the original feature was labeled as ``obsolescent'' in ISO C. -\difficulty -Syntactic transformation. -Facilities for producing explicit function declarations are fairly -widespread commercially. -\howwide -Common. - \diffref{expr.post.incr,expr.pre.incr} \change Decrement operator is not allowed with \keyword{bool} operand. @@ -2222,13 +2325,12 @@ \effect Change to semantics of well-defined feature. Some C expressions that implicitly rely on lvalue-to-rvalue -conversions will yield different results. For example, - +conversions will yield different results. +For example, \begin{codeblock} char arr[100]; sizeof(0, arr) \end{codeblock} - yields \tcode{100} in \Cpp{} and @@ -2250,8 +2352,8 @@ block. Allowing jump past initializers would require complicated runtime determination of allocation. -Furthermore, any use of the uninitialized object could be a -disaster. +Furthermore, many operations on such an uninitialized object +have undefined behavior. With this simple compile-time rule, \Cpp{} assures that if an initialized variable is in scope, then it has assuredly been initialized. @@ -2307,8 +2409,8 @@ with a type. In \Cpp{}, class members can be declared with the \keyword{static} storage class specifier. -Allowing storage class specifiers on type -declarations could render the code confusing for users. +Storage class specifiers on type +declarations can be confusing for users. \effect Deletion of semantically well-defined feature. \difficulty @@ -2374,48 +2476,11 @@ \howwide Seldom. -\diffref{dcl.type} -\change -Banning implicit \tcode{int}. - -In \Cpp{} a -\grammarterm{decl-specifier-seq} -must contain a -\grammarterm{type-specifier}{}, unless -it is followed by a declarator for a constructor, a destructor, or a -conversion function. -In the following example, the -left-hand column presents valid C; -the right-hand column presents -equivalent \Cpp{}: - -\begin{codeblock} -void f(const parm); void f(const int parm); -const n = 3; const int n = 3; -main() int main() - @\commentellip@ @\commentellip@ -\end{codeblock} - -\rationale -In \Cpp{}, implicit int creates several opportunities for -ambiguity between expressions involving function-like -casts and declarations. -Explicit declaration is increasingly considered -to be proper style. -Liaison with WG14 (C) indicated support for (at least) -deprecating implicit int in the next revision of C. -\effect -Deletion of semantically well-defined feature. -\difficulty -Syntactic transformation. -Can be automated. -\howwide -Common. - \diffref{dcl.spec.auto} \change The keyword \keyword{auto} cannot be used as a storage class specifier. +Example: \begin{codeblock} void f() { auto int x; // valid C, invalid \Cpp{} @@ -2439,7 +2504,6 @@ In C, an empty parameter list means that the number and type of the function arguments are unknown. Example: - \begin{codeblock} int f(); // means \tcode{int f(void)} in \Cpp{} // \tcode{int f(} unknown \tcode{)} in C @@ -2467,7 +2531,6 @@ In C, these type definitions are allowed. Example: - \begin{codeblock} void f( struct S { int a; } arg ) {} // valid C, invalid \Cpp{} enum E { A, B, C } f() {} // valid C, invalid \Cpp{} @@ -2608,6 +2671,27 @@ Taking the size of an enumerator is not a common C coding practice. +\diffref{dcl.align} +\change +In \Cpp{}, +an \grammarterm{alignment-specifier} is an \grammarterm{attribute-specifier}. +In C, an \grammarterm{alignment-specifier} is a \gterm{declaration-specifier}. + +Example: +\begin{codeblock} +#include +unsigned alignas(8) int x; // valid C, invalid \Cpp{} +unsigned int y alignas(8); // valid \Cpp{}, invalid C +\end{codeblock} +\rationale +\Cpp{} requires unambiguous placement of the \grammarterm{alignment-specifier}. +\effect +Deletion of semantically well-defined feature. +\difficulty +Syntactic transformation. +\howwide +Seldom. + \rSec2[diff.class]{\ref{class}: classes} \diffref{class.name} [see also \ref{dcl.typedef}] @@ -2700,8 +2784,8 @@ \indextext{bit-field!implementation-defined sign of}% Bit-fields of type plain \keyword{int} are signed. \rationale -Leaving the choice of signedness to implementations could lead to -inconsistent definitions of template specializations. For consistency, +The signedness needs to be consistent among template specializations. +For consistency, the implementation freedom was eliminated for non-dependent types, too. \effect diff --git a/source/concepts.tex b/source/concepts.tex index ac641ec5ce..801cb8ec57 100644 --- a/source/concepts.tex +++ b/source/concepts.tex @@ -169,6 +169,7 @@ \indexheader{concepts}% \begin{codeblock} +// all freestanding namespace std { // \ref{concepts.lang}, language-related concepts // \ref{concept.same}, concept \libconcept{same_as} @@ -848,6 +849,16 @@ Subclause \ref{concepts.compare} describes concepts that establish relationships and orderings on values of possibly differing object types. +\pnum +Given an expression \tcode{E} and a type \tcode{C}, +let \tcode{\exposid{CONVERT_TO_LVALUE}(E)} be: +\begin{itemize} +\item +\tcode{static_cast(as_const(E))} if that is a valid expression, and +\item +\tcode{static_cast(std::move(E))} otherwise. +\end{itemize} + \rSec2[concept.booleantestable]{Boolean testability} \pnum @@ -981,9 +992,45 @@ \tcode{true_type}\iref{meta.type.synop}, \tcode{int*}, and \tcode{bitset::reference}\iref{template.bitset} -model \exposconceptx{boolean\--testable}{boolean-testable}. +model \exposconcept{boolean-testable}. \end{example} +\rSec2[concept.comparisoncommontype]{Comparison common types} + +\begin{itemdecl} +template> + concept @\defexposconcept{comparison-common-type-with-impl}@ = // \expos + @\libconcept{same_as}@, + common_reference_t> && + requires { + requires @\libconcept{convertible_to}@ || @\libconcept{convertible_to}@; + requires @\libconcept{convertible_to}@ || @\libconcept{convertible_to}@; + }; + +template + concept @\defexposconcept{comparison-common-type-with}@ = // \expos + @\exposconcept{comparison-common-type-with-impl}@, remove_cvref_t>; +\end{itemdecl} + +\pnum +Let \tcode{C} be \tcode{common_reference_t}. +Let \tcode{t1} and \tcode{t2} be equality-preserving expressions +that are lvalues of type \tcode{remove_cvref_t}, and +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: +\begin{itemize} +\item +\tcode{\exposid{CONVERT_TO_LVALUE}(t1)} equals +\tcode{\exposid{CONVERT_TO_LVALUE}(t2)} +if and only if \tcode{t1} equals \tcode{t2}, and +\item +\tcode{\exposid{CONVERT_TO_LVALUE}(u1)} equals +\tcode{\exposid{CONVERT_TO_LVALUE}(u2)} +if and only if \tcode{u1} equals \tcode{u2} +\end{itemize} + \rSec2[concept.equalitycomparable]{Concept \cname{equality_comparable}} \begin{itemdecl} @@ -1005,7 +1052,7 @@ \tcode{const remove_reference_t} and \tcode{const remove_reference_t} respectively. \tcode{T} and \tcode{U} model -\tcode{\placeholder{weakly-equality-comparable-with}} only if +\tcode{\exposconcept{weakly-equality-comparable-with}} only if \begin{itemize} \item \tcode{t == u}, \tcode{u == t}, \tcode{t != u}, and \tcode{u != t} have the same domain. @@ -1038,7 +1085,7 @@ template concept @\deflibconcept{equality_comparable_with}@ = @\libconcept{equality_comparable}@ && @\libconcept{equality_comparable}@ && - @\libconcept{common_reference_with}@&, const remove_reference_t&> && + @\exposconcept{comparison-common-type-with}@ && @\libconcept{equality_comparable}@< common_reference_t< const remove_reference_t&, @@ -1049,15 +1096,21 @@ \begin{itemdescr} \pnum Given types \tcode{T} and \tcode{U}, -let \tcode{t} be an lvalue of type \tcode{const remove_reference_t}, -\tcode{u} be an lvalue of type \tcode{const remove_reference_t}, -and \tcode{C} be: +let \tcode{t} and \tcode{t2} be lvalues +denoting distinct equal objects of types \tcode{const remove_reference_t} and +\tcode{remove_cvref_t}, respectively, +let \tcode{u} and \tcode{u2} be lvalues +denoting distinct equal objects of types \tcode{const remove_reference_t} and +\tcode{remove_cvref_t}, respectively, and +let \tcode{C} be: \begin{codeblock} common_reference_t&, const remove_reference_t&> \end{codeblock} \tcode{T} and \tcode{U} model \tcode{\libconcept{equality_comparable_with}} only if -\tcode{bool(t == u) == bool(C(t) == C(u))}. +\begin{codeblock} +bool(t == u) == bool(@\exposid{CONVERT_TO_LVALUE}@(t2) == @\exposid{CONVERT_TO_LVALUE}@(u2)) +\end{codeblock} \end{itemdescr} \rSec2[concept.totallyordered]{Concept \cname{totally_ordered}} @@ -1100,24 +1153,27 @@ \begin{itemdescr} \pnum Given types \tcode{T} and \tcode{U}, -let \tcode{t} be an lvalue of type \tcode{const remove_reference_t}, -\tcode{u} be an lvalue of type \tcode{const remove_reference_t}, -and \tcode{C} be: +let \tcode{t} and \tcode{t2} be lvalues +denoting distinct equal objects of types \tcode{const remove_reference_t} and +\tcode{remove_cvref_t}, respectively, +let \tcode{u} and \tcode{u2} be lvalues +denoting distinct equal objects of types \tcode{const remove_reference_t} and +\tcode{remove_cvref_t}, respectively, and +let \tcode{C} be: \begin{codeblock} common_reference_t&, const remove_reference_t&> \end{codeblock} \tcode{T} and \tcode{U} model \tcode{\libconcept{totally_ordered_with}} only if - \begin{itemize} -\item \tcode{bool(t < u) == bool(C(t) < C(u)).} -\item \tcode{bool(t > u) == bool(C(t) > C(u)).} -\item \tcode{bool(t <= u) == bool(C(t) <= C(u)).} -\item \tcode{bool(t >= u) == bool(C(t) >= C(u)).} -\item \tcode{bool(u < t) == bool(C(u) < C(t)).} -\item \tcode{bool(u > t) == bool(C(u) > C(t)).} -\item \tcode{bool(u <= t) == bool(C(u) <= C(t)).} -\item \tcode{bool(u >= t) == bool(C(u) >= C(t)).} +\item \tcode{bool(t < u) == bool(\exposid{CONVERT_TO_LVALUE}(t2) < \exposid{CONVERT_TO_LVALUE}(u2))}. +\item \tcode{bool(t > u) == bool(\exposid{CONVERT_TO_LVALUE}(t2) > \exposid{CONVERT_TO_LVALUE}(u2))}. +\item \tcode{bool(t <= u) == bool(\exposid{CONVERT_TO_LVALUE}(t2) <= \exposid{CONVERT_TO_LVALUE}(u2))}. +\item \tcode{bool(t >= u) == bool(\exposid{CONVERT_TO_LVALUE}(t2) >= \exposid{CONVERT_TO_LVALUE}(u2))}. +\item \tcode{bool(u < t) == bool(\exposid{CONVERT_TO_LVALUE}(u2) < \exposid{CONVERT_TO_LVALUE}(t2))}. +\item \tcode{bool(u > t) == bool(\exposid{CONVERT_TO_LVALUE}(u2) > \exposid{CONVERT_TO_LVALUE}(t2))}. +\item \tcode{bool(u <= t) == bool(\exposid{CONVERT_TO_LVALUE}(u2) <= \exposid{CONVERT_TO_LVALUE}(t2))}. +\item \tcode{bool(u >= t) == bool(\exposid{CONVERT_TO_LVALUE}(u2) >= \exposid{CONVERT_TO_LVALUE}(t2))}. \end{itemize} \end{itemdescr} diff --git a/source/config.tex b/source/config.tex index 5f56bc933e..f5acf7b1e1 100644 --- a/source/config.tex +++ b/source/config.tex @@ -1,8 +1,8 @@ %!TEX root = std.tex %%-------------------------------------------------- %% Version numbers -\newcommand{\docno}{N4910} -\newcommand{\prevdocno}{N4901} +\newcommand{\docno}{N4917} +\newcommand{\prevdocno}{N4910} \newcommand{\cppver}{202002L} %% Release date diff --git a/source/containers.tex b/source/containers.tex index 258a4e7ffb..7d02506cbe 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -26,11 +26,11 @@ \ref{unord} & Unordered associative containers & \tcode{}, \tcode{} \\ \rowsep \ref{container.adaptors} & Container adaptors & - \tcode{}, \tcode{} \\ \rowsep -\ref{views} & Views & \tcode{} \\ + \tcode{}, \tcode{}, \tcode{}, \tcode{} \\ \rowsep +\ref{views} & Views & + \tcode{}, \tcode{} \\ \end{libsumtab} - \rSec1[container.requirements]{Requirements}% \indextext{requirements!container} @@ -203,7 +203,7 @@ that can represent any non-negative value of \tcode{X::difference_type}. \end{itemdescr} -\begin{itemdecl}{} +\begin{itemdecl} X u; X u = X(); \end{itemdecl} @@ -1237,8 +1237,14 @@ \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 -make it easy to construct abstract data types, such as \tcode{stack}s or \tcode{queue}s, out of -the basic sequence container kinds (or out of other kinds of sequence containers that the user defines). +make it easy to construct abstract data types, +such as \tcode{stack}s, +\tcode{queue}s, +\tcode{flat_map}s, +\tcode{flat_multimap}s, +\tcode{flat_set}s, or +\tcode{flat_multiset}s, out of +the basic sequence container kinds (or out of other program-defined sequence containers). \pnum \begin{note} @@ -1371,7 +1377,7 @@ from \tcode{*ranges::begin(rg)}. For \tcode{vector}, if \tcode{R} models -neither \libconcept{sized_range} nor \libconcept{forward_range}, +neither \tcode{ranges::\libconcept{sized_range}} nor \tcode{ranges::\libconcept{forward_range}}, \tcode{T} is also \oldconcept{MoveInsertable} into \tcode{X}. \pnum @@ -1727,7 +1733,7 @@ from \tcode{*ranges::begin(rg)}. For \tcode{vector}, if \tcode{R} models -neither \libconcept{sized_range} nor \libconcept{forward_range}, +neither \tcode{ranges::\libconcept{sized_range}} nor \tcode{ranges::\libconcept{forward_range}}, \tcode{T} is also \oldconcept{MoveInsertable} into \tcode{X}. \tcode{rg} and \tcode{a} do not overlap. @@ -2518,6 +2524,12 @@ \tcode{map} and \tcode{multimap}. +The library also provides container adaptors +that make it easy to construct abstract data types, +such as \tcode{flat_map}s, \tcode{flat_multimap}s, +\tcode{flat_set}s, or \tcode{flat_multiset}s, +out of the basic sequence container kinds +(or out of other program-defined sequence containers). \pnum Each associative container is parameterized on @@ -2851,7 +2863,7 @@ \pnum \complexity $N \log N$ in general, where $N$ has the value \tcode{distance(i, j)}; -linear if \range{i}{j} is sorted with \tcode{value_comp()}. +linear if \range{i}{j} is sorted with respect to \tcode{value_comp()}. \end{itemdescr} \indexlibraryctor{set}% @@ -2878,7 +2890,7 @@ \pnum \complexity $N \log N$ in general, where $N$ has the value \tcode{distance(i, j)}; -linear if \range{i}{j} is sorted with \tcode{value_comp()}. +linear if \range{i}{j} is sorted with respect to \tcode{value_comp()}. \end{itemdescr} \indexlibraryctor{set}% @@ -2905,7 +2917,7 @@ \pnum \complexity $N \log N$ in general, where $N$ has the value \tcode{ranges::distance(rg)}; -linear if \tcode{rg} is sorted with \tcode{value_comp()}. +linear if \tcode{rg} is sorted with respect to \tcode{value_comp()}. \end{itemdescr} \indexlibraryctor{set}% @@ -2984,7 +2996,7 @@ \pnum \complexity $N \log N$ in general, where $N$ has the value \tcode{il.size() + a.size()}; -linear if \range{il.begin()}{il.end()} is sorted with \tcode{value_comp()}. +linear if \range{il.begin()}{il.end()} is sorted with respect to \tcode{value_comp()}. \end{itemdescr} \indexordmem{key_comp}% @@ -5345,7 +5357,7 @@ \begin{itemdescr} \pnum \result -\tcode{iterator}; \tcode{const_iterator} for const \tcode{b}. +\tcode{iterator}; \tcode{const_iterator} for constant \tcode{b}. \pnum \returns @@ -5365,7 +5377,7 @@ \begin{itemdescr} \pnum \result -\tcode{iterator}; \tcode{const_iterator} for const \tcode{a_tran}. +\tcode{iterator}; \tcode{const_iterator} for constant \tcode{a_tran}. \pnum \returns @@ -5447,7 +5459,7 @@ \pnum \result \tcode{pair}; -\tcode{pair} for const \tcode{b}. +\tcode{pair} for constant \tcode{b}. \pnum \returns @@ -5468,7 +5480,7 @@ \pnum \result \tcode{pair}; -\tcode{pair} for const \tcode{a_tran}. +\tcode{pair} for constant \tcode{a_tran}. \pnum \returns @@ -5576,7 +5588,7 @@ \begin{itemdescr} \pnum \result -\tcode{local_iterator}; \tcode{const_local_iterator} for const \tcode{b}. +\tcode{local_iterator}; \tcode{const_local_iterator} for constant \tcode{b}. \pnum \expects @@ -5600,7 +5612,7 @@ \begin{itemdescr} \pnum \result -\tcode{local_iterator}; \tcode{const_local_iterator} for const \tcode{b}. +\tcode{local_iterator}; \tcode{const_local_iterator} for constant \tcode{b}. \pnum \expects @@ -5971,6 +5983,7 @@ 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); @@ -6006,6 +6019,7 @@ 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); @@ -6041,6 +6055,7 @@ 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); @@ -6076,6 +6091,7 @@ 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); @@ -6083,17 +6099,26 @@ constexpr typename vector::size_type erase_if(vector& c, Predicate pred); - // \ref{vector.bool}, class \tcode{vector} - template class vector; + 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 + inline constexpr bool @\exposid{is-vector-bool-reference}@ = @\seebelow@; // \expos // hash support template struct hash; template struct hash>; - namespace pmr { - template - using vector = std::vector>; - } + // \ref{vector.bool.fmt}, formatter specialization for \tcode{vector} + template requires @\exposid{is-vector-bool-reference}@ + struct formatter; } \end{codeblock} @@ -7333,7 +7358,7 @@ \begin{itemdescr} \pnum \effects -\tcode{insert_after(p, il.begin(), il.end())}. +\tcode{insert_after(position, il.begin(), il.end())}. \pnum \returns @@ -9094,14 +9119,14 @@ \end{codeblock} \end{itemdescr} -\rSec2[vector.bool]{Class \tcode{vector}} +\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 specialization of vector for -\tcode{bool} -elements is provided: - +To optimize space allocation, a partial specialization of \tcode{vector} for +\tcode{bool} elements is provided: \begin{codeblock} namespace std { template @@ -9279,6 +9304,68 @@ The specialization is enabled\iref{unord.hash}. \end{itemdescr} +\indexlibraryglobal{\exposid{is-vector-bool-reference}}% +\begin{itemdecl} +template + inline 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} + \rSec1[associative]{Associative containers} \rSec2[associative.general]{In general} @@ -9296,14 +9383,14 @@ typename iterator_traits::value_type; // \expos template using @\placeholder{iter-key-type}@ = remove_const_t< - typename iterator_traits::value_type::first_type>; // \expos + tuple_element_t<0, @\exposid{iter-value-type}@>>; // \expos template using @\placeholder{iter-mapped-type}@ = - typename iterator_traits::value_type::second_type; // \expos + tuple_element_t<1, @\exposid{iter-value-type}@>; // \expos template using @\placeholder{iter-to-alloc-type}@ = pair< - add_const_t::value_type::first_type>, - typename iterator_traits::value_type::second_type>; // \expos + add_const_t>>, + tuple_element_t<1, @\exposid{iter-value-type}@>>; // \expos template using @\exposid{range-key-type}@ = remove_const_t::first_type>; // \expos @@ -9341,6 +9428,7 @@ map& y) noexcept(noexcept(x.swap(y))); + // \ref{map.erasure}, erasure for \tcode{map} template typename map::size_type erase_if(map& c, Predicate pred); @@ -9363,6 +9451,7 @@ multimap& y) noexcept(noexcept(x.swap(y))); + // \ref{multimap.erasure}, erasure for \tcode{multimap} template typename multimap::size_type erase_if(multimap& c, Predicate pred); @@ -9403,6 +9492,7 @@ 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); @@ -9423,6 +9513,7 @@ 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); @@ -9444,7 +9535,7 @@ \indexlibraryglobal{map}% \pnum A \tcode{map} is an associative container that -supports unique keys (contains at most one of each key value) and +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. The \tcode{map} class supports bidirectional iterators. @@ -9741,7 +9832,7 @@ \complexity Linear in $N$ if the range \range{first}{last} -is already sorted using \tcode{comp} +is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{last - first}. \end{itemdescr} @@ -9761,7 +9852,7 @@ \pnum \complexity -Linear in $N$ if \tcode{rg} is already sorted using \tcode{comp} and +Linear in $N$ if \tcode{rg} is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{ranges::distance(rg)}. \end{itemdescr} @@ -9786,7 +9877,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return try_emplace(move(x)).first->second;} +Equivalent to: \tcode{return try_emplace(std::move(x)).first->second;} \end{itemdescr} \indexlibrarymember{at}{map}% @@ -9924,7 +10015,7 @@ \pnum \expects \tcode{value_type} is \oldconcept{EmplaceConstructible} into \tcode{map} -from \tcode{k}, \tcode{forward(obj)}. +from \tcode{k}, \tcode{std::forward(obj)}. \pnum \effects @@ -9964,7 +10055,7 @@ \pnum \expects \tcode{value_type} is \oldconcept{EmplaceConstructible} into \tcode{map} -from \tcode{move(k)}, \tcode{forward(obj)}. +from \tcode{std::move(k)}, \tcode{std::for\-ward(obj)}. \pnum \effects @@ -10022,7 +10113,7 @@ \indexlibraryglobal{multimap}% A \tcode{multimap} -is an associative container that supports equivalent keys (possibly containing multiple copies of +is an associative container 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. @@ -10303,7 +10394,7 @@ \complexity Linear in $N$ if the range \range{first}{last} -is already sorted using \tcode{comp} +is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{last - first}. @@ -10324,7 +10415,7 @@ \pnum \complexity -Linear in $N$ if \tcode{rg} is already sorted using \tcode{comp} and +Linear in $N$ if \tcode{rg} is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{ranges::distance(rg)}. \end{itemdescr} @@ -10382,7 +10473,7 @@ \indexlibraryglobal{set}% A \tcode{set} -is an associative container that supports unique keys (contains at most one of each key value) and +is an associative container that supports unique keys (i.e., contains at most one of each key value) and provides for fast retrieval of the keys themselves. The \tcode{set} class @@ -10515,7 +10606,8 @@ insert_return_type insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position); + 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); @@ -10610,7 +10702,7 @@ \begin{itemdescr} \pnum \effects -Constructs an empty \tcode{set} using the specified comparison objects and allocator. +Constructs an empty \tcode{set} using the specified comparison object and allocator. \pnum \complexity @@ -10637,7 +10729,7 @@ \complexity Linear in $N$ if the range \range{first}{last} -is already sorted using \tcode{comp} +is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{last - first}. @@ -10657,7 +10749,7 @@ \pnum \complexity -Linear in $N$ if \tcode{rg} is already sorted using \tcode{comp} and +Linear in $N$ if \tcode{rg} is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{ranges::distance(rg)}. \end{itemdescr} @@ -10695,7 +10787,7 @@ \indexlibraryglobal{multiset}% A \tcode{multiset} -is an associative container that supports equivalent keys (possibly contains multiple copies of +is an associative container that supports equivalent keys (i.e., possibly contains multiple copies of the same key value) and provides for fast retrieval of the keys themselves. The \tcode{multiset} class @@ -10827,7 +10919,8 @@ iterator insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position); + 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); @@ -10950,7 +11043,7 @@ Linear in $N$ if the range \range{first}{last} -is already sorted using \tcode{comp} and otherwise $N \log N$, +is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{last - first}. \end{itemdescr} @@ -10970,7 +11063,7 @@ \pnum \complexity -Linear in $N$ if \tcode{rg} is already sorted using \tcode{comp} and +Linear in $N$ if \tcode{rg} is already sorted with respect to \tcode{comp} and otherwise $N \log N$, where $N$ is \tcode{ranges::distance(rg)}. \end{itemdescr} @@ -11060,10 +11153,12 @@ unordered_multimap& y) noexcept(noexcept(x.swap(y))); + // \ref{unord.map.erasure}, erasure for \tcode{unordered_map} template 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 erase_if(unordered_multimap& c, Predicate pred); @@ -11130,10 +11225,12 @@ 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); @@ -11174,7 +11271,12 @@ of a container\iref{container.reqmts}, of an allocator-aware container\iref{container.alloc.reqmts}, and of an unordered associative container\iref{unord.req}. -It provides the operations described in the preceding requirements table for unique keys; that is, an \tcode{unordered_map} supports the \tcode{a_uniq} operations in that table, not the \tcode{a_eq} operations. For an \tcode{unordered_map} the \tcode{key type} is \tcode{Key}, the mapped type is \tcode{T}, and the value type is \tcode{pair}. +It provides the operations described in the preceding requirements table for unique keys; +that is, an \tcode{unordered_map} supports the \tcode{a_uniq} operations in that table, +not the \tcode{a_eq} operations. +For an \tcode{unordered_map} the \tcode{key_type} is \tcode{Key}, +the \tcode{mapped_type} is \tcode{T}, +and the \tcode{value_type} is \tcode{pair}. \pnum Subclause~\ref{unord.map} only describes operations on \tcode{unordered_map} that @@ -11431,7 +11533,7 @@ -> unordered_map<@\placeholder{iter-key-type}@, @\placeholder{iter-mapped-type}@, Hash, equal_to<@\placeholder{iter-key-type}@>, Allocator>; - template + template unordered_map(from_range_t, R&&, typename @\seebelow@::size_type, Allocator) -> unordered_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, hash<@\exposid{range-key-type}@>, equal_to<@\exposid{range-key-type}@>, Allocator>; @@ -11553,7 +11655,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return try_emplace(move(k)).first->second;} +Equivalent to: \tcode{return try_emplace(std::move(k)).first->second;} \end{itemdescr} \indexlibrarymember{unordered_map}{at}% @@ -11814,8 +11916,9 @@ It provides the operations described in the preceding requirements table for equivalent keys; that is, an \tcode{unordered_multimap} supports the \tcode{a_eq} operations in that table, not the \tcode{a_uniq} operations. -For an \tcode{unordered_multimap} the \tcode{key type} is \tcode{Key}, the -mapped type is \tcode{T}, and the value type is \tcode{pair}. +For an \tcode{unordered_multimap} the \tcode{key_type} is \tcode{Key}, +the \tcode{mapped_type} is \tcode{T}, +and the \tcode{value_type} is \tcode{pair}. \pnum Subclause~\ref{unord.multimap} only describes operations on \tcode{unordered_multimap} @@ -12233,7 +12336,13 @@ of a container\iref{container.reqmts}, of an allocator-aware container\iref{container.alloc.reqmts}, of an unordered associative container\iref{unord.req}. -It provides the operations described in the preceding requirements table for unique keys; that is, an \tcode{unordered_set} supports the \tcode{a_uniq} operations in that table, not the \tcode{a_eq} operations. For an \tcode{unordered_set} the \tcode{key type} and the value type are both \tcode{Key}. The \tcode{iterator} and \tcode{const_iterator} types are both constant iterator types. It is unspecified whether they are the same type. +It provides the operations described in the preceding requirements table for unique keys; +that is, an \tcode{unordered_set} supports the \tcode{a_uniq} operations in that table, +not the \tcode{a_eq} operations. +For an \tcode{unordered_set} the \tcode{key_type} +and the \tcode{value_type} are both \tcode{Key}. +The \tcode{iterator} and \tcode{const_iterator} types are both constant iterator types. +It is unspecified whether they are the same type. \pnum Subclause~\ref{unord.set} only describes operations on \tcode{unordered_set} that @@ -12359,7 +12468,8 @@ insert_return_type insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position); + 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); @@ -12603,7 +12713,7 @@ It provides the operations described in the preceding requirements table for equivalent keys; that is, an \tcode{unordered_multiset} supports the \tcode{a_eq} operations in that table, not the \tcode{a_uniq} operations. -For an \tcode{unordered_multiset} the \tcode{key type} and the value type are +For an \tcode{unordered_multiset} the \tcode{key_type} and the \tcode{value_type} are both \tcode{Key}. The \tcode{iterator} and \tcode{const_iterator} types are both constant iterator types. It is unspecified whether they are the same type. @@ -12732,7 +12842,8 @@ iterator insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); - iterator erase(iterator position); + 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); @@ -12958,21 +13069,41 @@ \rSec2[container.adaptors.general]{In general} \pnum -The headers \libheader{queue} and \libheader{stack} define the container adaptors -\tcode{queue}, \tcode{priority_queue}, and \tcode{stack}. +The headers +\libheader{queue}, +\libheader{stack}, +\libheader{flat_map}, +and \libheader{flat_set} +define the container adaptors +\tcode{queue} and \tcode{priority_queue}, +\tcode{stack}, +\tcode{flat_map} and \tcode{flat_multimap}, +and \tcode{flat_set} and \tcode{flat_multiset}, +respectively. \pnum -The container adaptors each take a \tcode{Container} template parameter, and each constructor takes -a \tcode{Container} reference argument. This container is copied into the \tcode{Container} member -of each adaptor. If the container takes an allocator, then a compatible allocator may be passed in +Each container adaptor takes +one or more template parameters +named \tcode{Container}, \tcode{KeyContainer}, or \tcode{MappedContainer} +that denote the types of containers that the container adaptor adapts. +Each container adaptor has at least one constructor +that takes a reference argument to one or more such template parameters. +For each constructor reference argument to a container \tcode{C}, +the constructor copies the container into the container adaptor. +If \tcode{C} takes an allocator, then a compatible allocator may be passed in to the adaptor's constructor. Otherwise, normal copy or move construction is used for the container argument. -The first template parameter \tcode{T} of the container adaptors +For the container adaptors +that take a single container template parameter \tcode{Container}, +the first template parameter \tcode{T} of the container adaptor shall denote the same type as \tcode{Container::value_type}. \pnum For container adaptors, no \tcode{swap} function throws an exception unless that -exception is thrown by the swap of the adaptor's \tcode{Container} or +exception is thrown by the swap of the adaptor's +\tcode{Container}, +\tcode{KeyContainer}, +\tcode{MappedContainer}, or \tcode{Compare} object (if any). \pnum @@ -12981,21 +13112,51 @@ if it has an \tcode{InputIterator} template parameter and a type that does not qualify as an input iterator is deduced for that parameter. +\pnum +For container adaptors that have them, +the \tcode{insert}, \tcode{emplace}, and \tcode{erase} members +affect the validity of iterators, references, and pointers +to the adaptor's container(s) in the same way that +the containers' respective +\tcode{insert}, \tcode{emplace}, and \tcode{erase} members do. +\begin{example} +A call to \tcode{flat_map::insert} +can invalidate all iterators to the \tcode{flat_map}. +\end{example} + \pnum A deduction guide for a container adaptor shall not participate in overload resolution if any of the following are true: \begin{itemize} \item It has an \tcode{InputIterator} template parameter and a type that does not qualify as an input iterator is deduced for that parameter. \item It has a \tcode{Compare} template parameter and a type that qualifies as an allocator is deduced for that parameter. -\item It has a \tcode{Container} template parameter and a type that qualifies as an allocator is deduced for that parameter. -\item It has no \tcode{Container} template parameter, and it has an \tcode{Allocator} template parameter, and a type that does not qualify as an allocator is deduced for that parameter. +\item It has a \tcode{Container}, \tcode{KeyContainer}, or \tcode{MappedContainer} template parameter and a type that qualifies as an allocator is deduced for that parameter. +\item It has no \tcode{Container}, \tcode{KeyContainer}, or \tcode{MappedContainer} template parameter, and it has an \tcode{Allocator} template parameter, and a type that does not qualify as an allocator is deduced for that parameter. \item It has both \tcode{Container} and \tcode{Allocator} template parameters, and \tcode{uses_allocator_v} is \tcode{false}. +\item It has both \tcode{KeyContainer} and \tcode{Allocator} template parameters, and +\tcode{uses_allocator_v} is \tcode{false}. +\item It has both \tcode{MappedContainer} and \tcode{Allocator} template parameters, and +\tcode{uses_allocator_v} is \tcode{false}. \end{itemize} \pnum The exposition-only alias template \exposid{iter-value-type} -defined in \ref{sequences.general} +defined in \ref{sequences.general} and +the exposition-only alias templates \exposid{iter-key-type} and \exposid{iter-mapped-type} +defined in \ref{associative.general} may appear in deduction guides for container adaptors. +\pnum +The following exposition-only alias templates may appear in deduction guides +for container adaptors: +\begin{codeblock} +template + using @\exposid{cont-key-type}@ = // \expos + remove_const_t; +template + using @\exposid{cont-mapped-type}@ = // \expos + typename Container::value_type::second_type; +\end{codeblock} + \rSec2[queue.syn]{Header \tcode{} synopsis} \indexheader{queue} @@ -13072,6 +13233,93 @@ } \end{codeblock} +\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 + 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 + typename flat_multimap::size_type + erase_if(flat_multimap& c, Predicate pred); +} +\end{codeblock} + +\rSec2[flat.set.syn]{Header \tcode{} synopsis}% +\indexheader{flat_set}% + +\begin{codeblock} +#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 + 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 + typename flat_multiset::size_type + erase_if(flat_multiset& c, Predicate pred); +} +\end{codeblock} + \rSec2[queue]{Class template \tcode{queue}} \rSec3[queue.defn]{Definition} @@ -13530,7 +13778,7 @@ priority_queue(InputIterator, InputIterator, Compare = Compare(), Container = Container()) -> priority_queue<@\exposid{iter-value-type}@, Container, Compare>; - template> + template>> priority_queue(from_range_t, R&&, Compare = Compare()) -> priority_queue, vector>, Compare>; @@ -14252,7 +14500,7 @@ \indexlibrarymember{operator>=}{stack}% \begin{itemdecl} template - bool operator>=(const stack& x, const stack& y); + bool operator>=(const stack& x, const stack& y); \end{itemdecl} \begin{itemdescr} @@ -14292,743 +14540,6114 @@ As if by \tcode{x.swap(y)}. \end{itemdescr} -\rSec1[views]{Views} +\rSec2[flat.map]{Class template \tcode{flat_map}} -\rSec2[views.general]{General} +\rSec3[flat.map.overview]{Overview} \pnum -The header \libheader{span} defines the view \tcode{span}. - -\rSec2[span.syn]{Header \tcode{} synopsis}% +\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}. -\indexheader{span}% -\begin{codeblock} -namespace std { - // constants - inline constexpr size_t @\libglobal{dynamic_extent}@ = numeric_limits::max(); +\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} - // \ref{views.span}, class template span - template - class span; +\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}. - template - inline constexpr bool ranges::enable_view> = true; - template - inline constexpr bool ranges::enable_borrowed_range> = true; +\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. - // \ref{span.objectrep}, views of object representation - template - span - as_bytes(span s) noexcept; +\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} - template - span - as_writable_bytes(span s) noexcept; -} -\end{codeblock} +\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} -\rSec2[views.span]{Class template \tcode{span}} +\pnum +Any sequence container\iref{sequence.reqmts} \tcode{C} +supporting \oldconcept{RandomAccessIterator} can be used +to instantiate \tcode{flat_map}, +as long as 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} -\rSec3[span.overview]{Overview} +\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}. \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. +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. \pnum -All member functions of \tcode{span} have constant time complexity. +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} -\indexlibraryglobal{span}% \begin{codeblock} namespace std { - template - class span { + template, + class KeyContainer = vector, class MappedContainer = vector> + class flat_map { 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 reverse_iterator = std::reverse_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 span(const span& other) noexcept = default; - template - constexpr explicit(@\seebelow@) span(const span& s) noexcept; + // 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; - ~span() noexcept = default; + 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); + } + }; - constexpr span& operator=(const span& other) noexcept = default; + struct containers { + key_container_type keys; + mapped_container_type values; + }; - // \ref{span.sub}, subviews - template - constexpr span first() const; - template - constexpr span last() const; - template - constexpr span subspan() const; + // \ref{flat.map.cons}, construct/copy/destroy + flat_map() : flat_map(key_compare()) { } - 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; + flat_map(key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); - // \ref{span.obs}, observers - constexpr size_type size() const noexcept; - constexpr size_type size_bytes() const noexcept; - [[nodiscard]] constexpr bool empty() const noexcept; + flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Allocator& a); - // \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; + 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); - // \ref{span.iterators}, iterator support - constexpr iterator begin() const noexcept; - constexpr iterator end() const noexcept; - constexpr reverse_iterator rbegin() const noexcept; - constexpr reverse_iterator rend() const noexcept; + 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); - private: - pointer data_; // \expos - size_type size_; // \expos - }; + 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 - span(It, EndOrSize) -> span>>; - template - span(T (&)[N]) -> span; - template - span(array&) -> span; - template - span(const array&) -> span; - template - span(R&&) -> span>>; -} -\end{codeblock} + 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); -\pnum -\tcode{span} is -a trivially copyable type\iref{term.trivially.copyable.type}. + // 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)); } + + 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); + + 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()); } + + containers extract() &&; + void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + 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); + + 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(flat_map& y) noexcept; + void clear() noexcept; + + // observers + key_compare key_comp() const; + 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; + + size_type count(const key_type& x) const; + template size_type count(const K& x) const; + + bool contains(const key_type& x) const; + template 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; + + 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; + + 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; + + friend bool operator==(const flat_map& x, const flat_map& y); + + friend @\exposid{synth-three-way-result}@ + operator<=>(const flat_map& x, const flat_map& y); + + friend void swap(flat_map& x, flat_map& y) noexcept + { x.swap(y); } + + private: + containers c; // \expos + key_compare compare; // \expos + + 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; + }; + }; + + template + flat_map(KeyContainer, MappedContainer) + -> flat_map, KeyContainer, MappedContainer>; + + template + flat_map(KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer) + -> flat_map, KeyContainer, MappedContainer>; + + template + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator) + -> flat_map, KeyContainer, MappedContainer>; + + template>> + flat_map(InputIterator, InputIterator, Compare = Compare()) + -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>> + flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_map<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>, + class Allocator> + flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare>; + + template + flat_map(from_range_t, R&&, Allocator) + -> flat_map<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@>; + + template> + flat_map(initializer_list>, Compare = Compare()) + -> flat_map; + + template> + flat_map(sorted_unique_t, initializer_list>, Compare = Compare()) + -> flat_map; + + template + struct uses_allocator, Allocator> + : bool_constant && + uses_allocator_v> { }; +} +\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. + +\rSec3[flat.map.cons]{Constructors} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +flat_map(key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}; +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 = ranges::zip_view(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} + +\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. +\end{itemdescr} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +template + flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); +\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_map(key_cont, mapped_cont)}, +except that \tcode{c.keys} and \tcode{c.values} are constructed with +uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Same as \tcode{flat_map(key_cont, mapped_cont)}. +\end{itemdescr} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}. + +\pnum +\complexity +Constant. +\end{itemdescr} + +\indexlibraryctor{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); +\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_map(s, key_cont, mapped_cont)}, +except that \tcode{c.keys} and \tcode{c.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibraryctor{flat_map}% +\begin{itemdecl} +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); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true}. + +\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}. +\end{itemdescr} + +\rSec3[flat.map.capacity]{Capacity} + +\indexlibrarymember{size}{flat_map}% +\begin{itemdecl} +size_type size() const noexcept; +\end{itemdecl} + +\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} + +\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} + +\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} + +\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} + +\begin{itemdescr} +\pnum +\constraints +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} is valid and +denotes a type. + +\pnum +\effects +Equivalent to: \tcode{return try_emplace(std::forward(x)).first->second;} +\end{itemdescr} + +\indexlibrarymember{at}{flat_map}% +\begin{itemdecl} +mapped_type& at(const key_type& x); +const mapped_type& at(const key_type& x) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A reference to the \tcode{mapped_type} corresponding +to \tcode{x} in \tcode{*this}. + +\pnum +\throws +An exception object of type \tcode{out_of_range} if +no such element is present. + +\pnum +\complexity +Logarithmic. +\end{itemdescr} + +\indexlibrarymember{at}{flat_map}% +\begin{itemdecl} +template mapped_type& at(const K& x); +template const mapped_type& at(const K& x) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The \grammarterm{qualified-id} \tcode{Compare::is_transparent} +is valid and denotes a type. + +\pnum +\expects +The expression \tcode{find(x)} is well-formed and has well-defined behavior. + +\pnum +\returns +A reference to the \tcode{mapped_type} corresponding to +\tcode{x} in \tcode{*this}. + +\pnum +\throws +An exception object of type \tcode{out_of_range} +if no such element is present. + +\pnum +\complexity +Logarithmic. +\end{itemdescr} + +\rSec3[flat.map.modifiers]{Modifiers} + +\indexlibrarymember{emplace}{flat_map}% +\begin{itemdecl} +template pair emplace(Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v, Arg...>} is \tcode{true}. + +\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} + +\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} + +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template pair insert(P&& x); +template iterator insert(const_iterator position, P&& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v, P>} 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} + +\indexlibrarymember{insert}{flat_map}% +\begin{itemdecl} +template + void insert(InputIterator first, InputIterator last); +\end{itemdecl} + +\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 = ranges::zip_view(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} + +\pnum +\complexity +$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_map}% +\begin{itemdecl} +template + void insert(sorted_unique_t, InputIterator first, InputIterator last); +\end{itemdecl} + +\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 = ranges::zip_view(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} + +\pnum +\complexity +Linear in $N$, where $N$ is \tcode{size()} after the operation. + +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. +\end{itemdescr} + +\indexlibrarymember{insert_range}{flat_map}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + void insert_range(R&& rg); +\end{itemdecl} + +\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 = ranges::zip_view(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} + +\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{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} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\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} + +\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 +The same as \tcode{emplace} for the first two overloads, and +the same as \tcode{emplace_hint} for the last two overloads. +\end{itemdescr} + +\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} + +\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} + +\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 +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} + +\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 +The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. +\end{itemdescr} + +\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} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_assignable_v} is \tcode{true} and +\tcode{is_constructible_v} is \tcode{true}. + +\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(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 +The same as \tcode{emplace} for the first two overloads and +the same as \tcode{emplace_hint} for the last two overloads. +\end{itemdescr} + +\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} + +\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} + +\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 +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(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 +The same as \tcode{emplace} and \tcode{emplace_hint}, respectively. +\end{itemdescr} + +\indexlibrarymember{swap}{flat_map}% +\begin{itemdecl} +void swap(flat_map& y) noexcept; +\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} +\end{itemdescr} + +\indexlibrarymember{extract}{flat_map}% +\begin{itemdecl} +containers extract() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{*this} is emptied, even if the function exits via an exception. + +\pnum +\returns +\tcode{std::move(c)}. +\end{itemdescr} + +\indexlibrarymember{replace}{flat_map}% +\begin{itemdecl} +void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); +\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. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +c.keys = std::move(key_cont); +c.values = std::move(mapped_cont); +\end{codeblock} +\end{itemdescr} + +\rSec3[flat.map.erasure]{Erasure} + +\indexlibrarymember{erase_if}{flat_map}% +\begin{itemdecl} +template + typename flat_map::size_type + erase_if(flat_map& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{Key} and \tcode{T} meet the \oldconcept{MoveAssignable} requirements. + +\pnum +\effects +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} + +\rSec2[flat.multimap]{Class template \tcode{flat_multimap}} + +\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} + +\pnum +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} + +\pnum +Any sequence container\iref{sequence.reqmts} \tcode{C} +supporting \oldconcept{RandomAccessIterator} can be used to +instantiate \tcode{flat_multimap}, +as long as 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} + +\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}. + +\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. + +\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. + +\rSec3[flat.multimap.defn]{Definition} + +\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; + + 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.multimap.cons}, construct/copy/destroy + flat_multimap() : flat_multimap(key_compare()) { } + + flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); + + flat_multimap(sorted_equivalent_t, + key_container_type key_cont, mapped_container_type mapped_cont); + template + flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, 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); + + template + flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), 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<@\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); + 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); + + 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); + + flat_multimap& 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; + + // capacity + [[nodiscard]] bool empty() const noexcept; + size_type size() const noexcept; + 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) + { 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 iterator insert(P&& x); + template + iterator insert(const_iterator position, P&&); + 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); + + 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()); } + + containers extract() &&; + void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + 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(flat_multimap&) noexcept; + void clear() noexcept; + + // observers + key_compare key_comp() const; + 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; + + size_type count(const key_type& x) const; + template size_type count(const K& x) const; + + bool contains(const key_type& x) const; + template 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; + + 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; + + 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; + + friend bool operator==(const flat_multimap& x, const flat_multimap& y); + + friend @\exposid{synth-three-way-result}@ + operator<=>(const flat_multimap& x, const flat_multimap& y); + + friend void swap(flat_multimap& x, flat_multimap& y) noexcept + { x.swap(y); } + + private: + containers c; // \expos + key_compare compare; // \expos + }; + + template + flat_multimap(KeyContainer, MappedContainer) + -> flat_multimap, KeyContainer, MappedContainer>; + + template + flat_multimap(KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer) + -> flat_multimap, KeyContainer, MappedContainer>; + + template + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator) + -> flat_multimap, KeyContainer, MappedContainer>; + + template>> + flat_multimap(InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>> + flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<@\exposid{iter-key-type}@, @\exposid{iter-mapped-type}@, Compare>; + + template>, + class Allocator> + flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@, Compare>; + + template + flat_multimap(from_range_t, R&&, Allocator) + -> flat_multimap<@\exposid{range-key-type}@, @\exposid{range-mapped-type}@>; + + 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} + +\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. + +\rSec3[flat.multimap.cons]{Constructors} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}; and +sorts the range \range{begin()}{end()} with respect to \tcode{value_comp()}. + +\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. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +template + flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, + const Allocator& a); +\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)}, +except that \tcode{c.keys} and \tcode{c.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Same as \tcode{flat_multimap(key_cont, mapped_cont)}. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +flat_multimap(sorted_equivalent_t, key_container_type key_cont, mapped_container_type mapped_cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{c.keys} with \tcode{std::move(key_cont)} and +\tcode{c.values} with \tcode{std::move(mapped_cont)}; +value-initializes \tcode{compare}. + +\pnum +\complexity +Constant. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +template + flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Allocator& a); +\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(s, key_cont, mapped_cont)}, +except that \tcode{c.keys} and \tcode{c.val\-ues} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibraryctor{flat_multimap}% +\begin{itemdecl} +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); +\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 the corresponding non-allocator constructors +except that \tcode{c.keys} and \tcode{c.values} are constructed +with uses-allocator construction\iref{allocator.uses.construction}. +\end{itemdescr} + +\rSec3[flat.multimap.erasure]{Erasure} + +\indexlibrarymember{erase_if}{flat_multimap}% +\begin{itemdecl} +template + typename flat_multimap::size_type + erase_if(flat_multimap& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{Key} and \tcode{T} meet the \oldconcept{MoveAssignable} requirements. + +\pnum +\effects +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} + +\rSec2[flat.set]{Class template \tcode{flat_set}} + +\rSec3[flat.set.overview]{Overview} + +\pnum +\indexlibraryglobal{flat_set}% +A \tcode{flat_set} 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 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_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_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.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_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_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 +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_set} 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, +the invariant is restored. +\begin{note} +This can result in the \tcode{flat_set}'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. +\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}. + +\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. + +\rSec3[flat.set.defn]{Definition} + +\begin{codeblock} +namespace std { + template, class KeyContainer = vector> + class @\libglobal{flat_set}@ { + 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_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; + + // \ref{flat.set.cons}, constructors + flat_set() : flat_set(key_compare()) { } + + explicit flat_set(container_type cont); + template + flat_set(const container_type& cont, const Allocator& a); + + flat_set(sorted_unique_t, container_type cont) + : @\exposid{c}@(std::move(cont)), @\exposid{compare}@(key_compare()) { } + template + flat_set(sorted_unique_t, const container_type& cont, 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()) + : @\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<@\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); + template<@\exposconcept{container-compatible-range}@ R> + flat_set(from_range_t, R&& rg, const key_compare& comp) + : flat_set(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); + + 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); + + flat_set& operator=(initializer_list); + + // 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; + + // capacity + [[nodiscard]] bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + // \ref{flat.set.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)); } + template pair insert(K&& 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 iterator insert(const_iterator hint, K&& x); + + 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); + + 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()); } + + container_type extract() &&; + 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); + + void swap(flat_set& y) noexcept; + void clear() noexcept; + + // observers + key_compare key_comp() const; + 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; + + size_type count(const key_type& x) const; + template size_type count(const K& x) const; + + bool contains(const key_type& x) const; + template 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; + + 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; + + 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; + + friend bool operator==(const flat_set& x, const flat_set& y); + + friend @\placeholder{synth-three-way-result}@ + operator<=>(const flat_set& x, const flat_set& y); + + friend void swap(flat_set& x, flat_set& y) noexcept { x.swap(y); } + + private: + container_type @\exposid{c}@; // \expos + key_compare @\exposid{compare}@; // \expos + }; + + template>> + flat_set(InputIterator, InputIterator, Compare = Compare()) + -> flat_set<@\placeholder{iter-value-type}@, Compare>; + + template>> + flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_set<@\placeholder{iter-value-type}@, Compare>; + + template>, + class Allocator = allocator>> + flat_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_set, Compare>; + + template + flat_set(from_range_t, R&&, Allocator) + -> flat_set, less>>; + + 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} +explicit flat_set(container_type cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{c} with \tcode{std::move(cont)}, +value-initializes \exposid{compare}, +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 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}% +\begin{itemdecl} +template + flat_set(const container_type& cont, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_set(cont)}, +except that \exposid{c} is constructed with +uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Same as \tcode{flat_set(cont)}. +\end{itemdescr} + +\indexlibraryctor{flat_set}% +\begin{itemdecl} +template + flat_set(sorted_unique_t s, const container_type& cont, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_set(s, cont)}, +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 + 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); +\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}. +\end{itemdescr} + +\rSec3[flat.set.modifiers]{Modifiers} + +\indexlibrarymember{insert}{flat_set}% +\begin{itemdecl} +template pair insert(K&& x); +template iterator insert(const_iterator hint, K&& x); +\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. + +\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))}. + +\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} + +\indexlibrarymember{insert}{flatset}% +\begin{itemdecl} +template + void insert(InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +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 +$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}% +\begin{itemdecl} +template + void insert(sorted_unique_t, InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{insert(first, last)}. + +\pnum +\complexity +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{distance(first, last)}. + +\pnum +\remarks +Since this operation performs an in-place merge, it may allocate memory. +\end{itemdescr} + +\indexlibrarymember{swap}{flat_set}% +\begin{itemdecl} +void swap(flat_set& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +ranges::swap(compare, y.compare); +ranges::swap(@\exposid{c}@, y.@\exposid{c}@); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{extract}{flatset}% +\begin{itemdecl} +container_type extract() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{*this} is emptied, even if the function exits via an exception. + +\pnum +\returns +\tcode{std::move(\exposid{c})}. +\end{itemdescr} + +\indexlibrarymember{replace}{flat_set}% +\begin{itemdecl} +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. + +\pnum +\effects +Equivalent to: \tcode{\exposid{c} = std::move(cont);} +\end{itemdescr} + +\rSec3[flat.set.erasure]{Erasure} + +\indexlibrarymember{erase_if}{flat_set}% +\begin{itemdecl} +template + typename flat_set::size_type + erase_if(flat_set& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto [erase_first, erase_last] = ranges::remove_if(c, pred); +auto n = erase_last - erase_first; +c.erase(erase_first, erase_last); +return n; +\end{codeblock} +\end{itemdescr} + +\rSec2[flat.multiset]{Class template \tcode{flat_multiset}} + +\rSec3[flat.multiset.overview]{Overview} + +\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}. + +\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} + +\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}. + +\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. + +\pnum +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.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} + +\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} + +\pnum +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 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. + +\rSec3[flat.multiset.defn]{Definition} + +\begin{codeblock} +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; + + // \ref{flat.multiset.cons}, constructors + flat_multiset() : flat_multiset(key_compare()) { } + + explicit flat_multiset(container_type cont); + template + flat_multiset(const container_type& cont, const Allocator& a); + + flat_multiset(sorted_equivalent_t, container_type cont) + : @\exposid{c}@(std::move(cont)), @\exposid{compare}@(key_compare()) { } + template + flat_multiset(sorted_equivalent_t, const container_type&, const Allocator& a); + + 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); + + 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<@\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); + + 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); + + flat_multiset& operator=(initializer_list); + + // 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; + + // capacity + [[nodiscard]] bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + // \ref{flat.multiset.modifiers}, modifiers + template iterator emplace(Args&&... args); + template + iterator emplace_hint(const_iterator position, Args&&... args); + + 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 + 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); + + 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()); } + + container_type extract() &&; + 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); + + void swap(flat_multiset& y) noexcept; + void clear() noexcept; + + // observers + key_compare key_comp() const; + 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; + + size_type count(const key_type& x) const; + template size_type count(const K& x) const; + + bool contains(const key_type& x) const; + template 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; + + 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; + + 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; + + friend bool operator==(const flat_multiset& x, const flat_multiset& y); + + friend @\placeholder{synth-three-way-result}@ + operator<=>(const flat_multiset& x, const flat_multiset& y); + + friend void swap(flat_multiset& x, flat_multiset& y) noexcept + { x.swap(y); } + + private: + container_type @\exposid{c}@; // \expos + key_compare @\exposid{compare}@; // \expos + }; + + template>> + flat_multiset(InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset<@\placeholder{iter-value-type}@, @\placeholder{iter-value-type}@, Compare>; + + template>> + flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset<@\placeholder{iter-value-type}@, @\placeholder{iter-value-type}@, Compare>; + + template>, + class Allocator = allocator>> + flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multiset, Compare>; + + template + flat_multiset(from_range_t, R&&, Allocator) + -> flat_multiset, less>>; + + template> + flat_multiset(initializer_list, Compare = Compare()) + -> flat_multiset; + + template> + flat_multiset(sorted_equivalent_t, initializer_list, Compare = Compare()) + -> flat_multiset; + + template + struct uses_allocator, Allocator> + : bool_constant> { }; +} +\end{codeblock} + +\rSec3[flat.multiset.cons]{Constructors} + +\indexlibraryctor{flat_multiset}% +\begin{itemdecl} +explicit flat_multiset(container_type cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{c} with \tcode{std::move(cont)}, +value-initializes \exposid{compare}, 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 +otherwise $N \log N$, where $N$ is the value of \tcode{cont.size()} before this call. +\end{itemdescr} + +\indexlibraryctor{flat_multiset}% +\begin{itemdecl} +template + flat_multiset(const container_type& cont, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_multiset(cont)}, +except that \exposid{c} is constructed with +uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Same as \tcode{flat_multiset(cont)}. +\end{itemdescr} + +\indexlibraryctor{flat_multiset}% +\begin{itemdecl} +template + flat_multiset(sorted_equivalent_t s, const container_type& cont, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{uses_allocator_v} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{flat_multiset(s, cont)}, +except that \exposid{c} is constructed with +uses-allocator construction\iref{allocator.uses.construction}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibraryctor{flat_multiset}% +\begin{itemdecl} +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); +\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}. +\end{itemdescr} + +\rSec3[flat.multiset.modifiers]{Modifiers} + +\indexlibrarymember{emplace}{flat_multiset}% +\begin{itemdecl} +template iterator emplace(Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +First, initializes an object \tcode{t} of type \tcode{key_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} + +\pnum +\returns +An iterator that points to the inserted element. +\end{itemdescr} + +\indexlibrarymember{insert}{flat_mulitset}% +\begin{itemdecl} +template + void insert(InputIterator first, InputIterator last); +\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. + +\pnum +\complexity +$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_multiset}% +\begin{itemdecl} +template + void insert(sorted_equivalent_t, InputIterator first, InputIterator last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{insert(first, last)}. + +\pnum +\complexity +Linear. +\end{itemdescr} + +\indexlibrarymember{swap}{flat_multiset}% +\begin{itemdecl} +void swap(flat_multiset& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +ranges::swap(compare, y.compare); +ranges::swap(c, y.c); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{extract}{flat_multiset}% +\begin{itemdecl} +container_type extract() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{*this} is emptied, even if the function exits via an exception. + +\pnum +\returns +\tcode{std::move(c)}. +\end{itemdescr} + +\indexlibrarymember{replace}{flat_multiset}% +\begin{itemdecl} +void replace(container_type&& cont); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The elements of \tcode{cont} are sorted with respect to \exposid{compare}. + +\pnum +\effects +Equivalent to: \tcode{c = std::move(cont);} +\end{itemdescr} + +\rSec3[flat.multiset.erasure]{Erasure} + +\indexlibrarymember{erase_if}{flat_multiset}% +\begin{itemdecl} +template + typename flat_multiset::size_type + erase_if(flat_multiset& c, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto [erase_first, erase_last] = ranges::remove_if(c, pred); +auto n = erase_last - erase_first; +c.erase(erase_first, erase_last); +return n; +\end{codeblock} +\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-adaptor}@ = // \expos + @\exposid{fmt-maybe-const}@<@\placeholder{adaptor-type}@, charT>; + formatter @\exposid{underlying_}@; // \expos + + public: + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\indexlibrarymember{parse}{formatter}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +\end{itemdescr} + +\indexlibrarymember{format}{formatter}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.format(r.c, ctx);} +\end{itemdescr} + +\rSec1[views]{Views} + +\rSec2[views.general]{General} + +\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. + +\rSec2[span.syn]{Header \tcode{} synopsis}% + +\indexheader{span}% +\begin{codeblock} +namespace std { + // constants + inline constexpr size_t @\libglobal{dynamic_extent}@ = numeric_limits::max(); + + // \ref{views.span}, class template \tcode{span} + template + class span; + + template + inline constexpr bool ranges::enable_view> = true; + template + inline constexpr bool ranges::enable_borrowed_range> = true; + + // \ref{span.objectrep}, views of object representation + template + span + as_bytes(span s) noexcept; + + template + span + as_writable_bytes(span s) noexcept; +} +\end{codeblock} + +\rSec2[views.span]{Class template \tcode{span}} + +\rSec3[span.overview]{Overview} + +\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. + +\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 span(const span& other) noexcept = default; + template + constexpr explicit(@\seebelow@) span(const span& s) noexcept; + + ~span() noexcept = default; + + 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; + + // \ref{span.obs}, observers + constexpr size_type size() const noexcept; + constexpr size_type size_bytes() const noexcept; + [[nodiscard]] constexpr bool empty() const noexcept; + + // \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; + + // \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(); } + + private: + pointer data_; // \expos + size_type size_; // \expos + }; + + 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} + +\pnum +\tcode{span} is +a trivially copyable type\iref{term.trivially.copyable.type}. + +\pnum +\tcode{ElementType} is required to be +a complete object type that is not an abstract class type. + +\rSec3[span.cons]{Constructors, copy, and assignment} + +\indexlibraryctor{span}% +\begin{itemdecl} +constexpr span() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{Extent == dynamic_extent || Extent == 0} is \tcode{true}. + +\pnum +\ensures +\tcode{size() == 0 \&\& data() == nullptr}. +\end{itemdescr} + +\indexlibraryctor{span}% +\begin{itemdecl} +template + constexpr explicit(extent != dynamic_extent) span(It first, size_type count); +\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} + +\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} + +\pnum +\effects +Initializes \tcode{data_} with \tcode{to_address(first)} and +\tcode{size_} with \tcode{count}. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibraryctor{span}% +\begin{itemdecl} +template + constexpr explicit(extent != dynamic_extent) span(It first, End last); +\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} + +\pnum +\effects +Initializes \tcode{data_} with \tcode{to_address(first)} and +\tcode{size_} with \tcode{last - first}. + +\pnum +\throws +When and what \tcode{last - first} throws. +\end{itemdescr} + +\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} + +\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} + +\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} + +\pnum +\ensures +\tcode{size() == N \&\& data() == data(arr)} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{span}% +\begin{itemdecl} +template constexpr explicit(extent != dynamic_extent) span(R&& r); +\end{itemdecl} + +\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} + +\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} + +\pnum +\effects +Initializes \tcode{data_} with \tcode{ranges::data(r)} and +\tcode{size_} with \tcode{ranges::size(r)}. + +\pnum +\throws +What and when \tcode{ranges::data(r)} and \tcode{ranges::size(r)} throw. +\end{itemdescr} + +\indexlibraryctor{span}% +\begin{itemdecl} +constexpr span(const span& other) noexcept = default; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{other.size() == size() \&\& other.data() == data()}. +\end{itemdescr} + +\indexlibraryctor{span}% +\begin{itemdecl} +template + constexpr explicit(@\seebelow@) span(const span& s) 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()}. + +\pnum +\remarks +The expression inside \keyword{explicit} is equivalent to: +\begin{codeblock} +extent != dynamic_extent && OtherExtent == dynamic_extent +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator=}{span}% +\begin{itemdecl} +constexpr span& operator=(const span& other) noexcept = default; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{size() == other.size() \&\& data() == other.data()}. +\end{itemdescr} + +\rSec3[span.deduct]{Deduction guides} + +\indexlibrary{\idxcode{span}!deduction guide}% +\begin{itemdecl} +template + span(It, EndOrSize) -> span>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{It} satisfies \libconcept{contiguous_iterator}. +\end{itemdescr} + +\indexlibrary{\idxcode{span}!deduction guide}% +\begin{itemdecl} +template + span(R&&) -> span>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. +\end{itemdescr} + +\rSec3[span.sub]{Subviews} + +\indexlibrarymember{span}{first}% +\begin{itemdecl} +template constexpr span first() const; +\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. +\end{itemdescr} + +\indexlibrarymember{span}{last}% +\begin{itemdecl} +template constexpr span last() const; +\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() + (size() - Count), Count\};} +where \tcode{R} is the return type. +\end{itemdescr} + +\indexlibrarymember{span}{subspan}% +\begin{itemdecl} +template + constexpr span subspan() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\begin{codeblock} +Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset) +\end{codeblock} +is \tcode{true}. + +\pnum +\expects +\begin{codeblock} +Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset) +\end{codeblock} +is \tcode{true}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return span( + data() + Offset, Count != dynamic_extent ? Count : size() - Offset); +\end{codeblock} + +\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} +\end{itemdescr} + +\indexlibrarymember{span}{first}% +\begin{itemdecl} +constexpr span first(size_type count) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{count <= size()} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return \{data(), count\};} +\end{itemdescr} + +\indexlibrarymember{span}{last}% +\begin{itemdecl} +constexpr span last(size_type count) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{count <= size()} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return \{data() + (size() - count), count\};} +\end{itemdescr} + +\indexlibrarymember{span}{subspan}% +\begin{itemdecl} +constexpr span subspan( + size_type offset, size_type count = dynamic_extent) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\begin{codeblock} +offset <= size() && (count == dynamic_extent || count <= size() - offset) +\end{codeblock} +is \tcode{true}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return {data() + offset, count == dynamic_extent ? size() - offset : count}; +\end{codeblock} +\end{itemdescr} + +\rSec3[span.obs]{Observers} + +\indexlibrarymember{span}{size}% +\begin{itemdecl} +constexpr size_type size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return size_;} +\end{itemdescr} + +\indexlibrarymember{span}{size_bytes}% +\begin{itemdecl} +constexpr size_type size_bytes() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return size() * sizeof(element_type);} +\end{itemdescr} + +\indexlibrarymember{span}{empty}% +\begin{itemdecl} +[[nodiscard]] constexpr bool empty() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return size() == 0;} +\end{itemdescr} + +\rSec3[span.elem]{Element access} + +\indexlibrary{\idxcode{operator[]}!\idxcode{span}}% +\begin{itemdecl} +constexpr reference operator[](size_type idx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{idx < size()} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return *(data() + idx);} +\end{itemdescr} + +\indexlibrarymember{span}{front}% +\begin{itemdecl} +constexpr reference front() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{empty()} is \tcode{false}. + +\pnum +\effects +Equivalent to: \tcode{return *data();} +\end{itemdescr} + +\indexlibrarymember{span}{back}% +\begin{itemdecl} +constexpr reference back() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{empty()} is \tcode{false}. + +\pnum +\effects +Equivalent to: \tcode{return *(data() + (size() - 1));} +\end{itemdescr} + +\indexlibrarymember{span}{data}% +\begin{itemdecl} +constexpr pointer data() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return data_;} +\end{itemdescr} + +\rSec3[span.iterators]{Iterator support} + +\indexlibrarymember{iterator}{span}% +\begin{itemdecl} +using iterator = @\impdefx{type of \tcode{span::iterator}}@; +\end{itemdecl} + +\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 +All requirements on container iterators\iref{container.requirements} apply to +\tcode{span::iterator} as well. +\end{itemdescr} + +\indexlibrarymember{span}{begin}% +\begin{itemdecl} +constexpr iterator begin() const noexcept; +\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()}. +\end{itemdescr} + +\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} + +\indexlibrarymember{span}{rbegin}% +\begin{itemdecl} +constexpr reverse_iterator rbegin() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return reverse_iterator(end());} +\end{itemdescr} + +\indexlibrarymember{span}{rend}% +\begin{itemdecl} +constexpr reverse_iterator rend() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return reverse_iterator(begin());} +\end{itemdescr} + + +\rSec3[span.objectrep]{Views of object representation} + +\indexlibraryglobal{as_bytes}% +\begin{itemdecl} +template + span + as_bytes(span s) noexcept; +\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. +\end{itemdescr} + +\indexlibraryglobal{as_writable_bytes}% +\begin{itemdecl} +template + span + as_writable_bytes(span s) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_const_v} is \tcode{false}. + +\pnum +\effects +Equivalent to: \tcode{return R\{reinterpret_cast(s.data()), s.size_bytes()\};} +where \tcode{R} is the return type. +\end{itemdescr} + +\rSec2[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; +} +\end{codeblock} + +\rSec2[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. + +\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$})$. + +\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} + +\rSec2[mdspan.extents]{Class template \tcode{extents}} + +\rSec3[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; + + // \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} + +\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} + +\pnum +Each specialization of \tcode{extents} models \libconcept{regular} and +is trivially copyable. + +\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$. + +\pnum +The $r^\text{th}$ interval of the multidimensional index space +represented by an \tcode{extents} object is $[0, D_r)$. + +\rSec3[mdspan.extents.expo]{Exposition-only helpers} + +\begin{itemdecl} +static constexpr rank_type @\exposid{dynamic-index}@(rank_type i) noexcept; // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\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} + +\begin{itemdecl} +static constexpr rank_type @\exposid{dynamic-index-inv}@(rank_type i) noexcept; // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{i < rank_dynamic()} is \tcode{true}. + +\pnum +\returns +The minimum value of $r$ +such that \tcode{\exposid{dynamic-index}($r$ + 1) == i + 1} is \tcode{true}. +\end{itemdescr} + +\begin{itemdecl} +constexpr size_t @\exposid{fwd-prod-of-extents}@(rank_type i) const noexcept; // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{i <= rank()} is \tcode{true}. + +\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}. +\end{itemdescr} + +\begin{itemdecl} +constexpr size_t @\exposid{rev-prod-of-extents}@(rank_type i) const noexcept; // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{i < rank()} is \tcode{true}. + +\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} + +\begin{itemdecl} +template + static constexpr auto @\exposid{index-cast}@(OtherIndexType&& i) noexcept; // \expos +\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} +\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} + +\rSec3[mdspan.extents.cons]{Constructors} + +\indexlibraryctor{extents}% +\begin{itemdecl} +template + constexpr explicit(@\seebelow@) + extents(const extents& other) noexcept; +\end{itemdecl} + +\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} + +\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} + +\pnum +\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} + +\indexlibraryctor{extents}% +\begin{itemdecl} +template + explicit constexpr extents(OtherIndexTypes... exts) 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))...\}}. + +\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}. +\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 +\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 nonnegative and +is representable as a value of type \tcode{index_type}. +\end{itemize} +\end{itemize} + +\pnum +\ensures +\tcode{*this == extents(exts_arr)} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{extents}% +\begin{itemdecl} +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 +\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 nonnegative and +is representable as a value of type \tcode{index_type} for every rank index $r$. +\end{itemize} +\end{itemize} + +\pnum +\effects +\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-extent}[$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\-tent}\tcode{[$d$]} +with \tcode{as_const(exts[\exposidnc{dynamic-index-inv}($d$)])}. +\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}. +\end{itemdescr} + +\rSec3[mdspan.extents.obs]{Observers of the multidimensional index space} + +\indexlibrarymember{static_extent}{extents}% +\begin{itemdecl} +static constexpr size_t static_extent(rank_type i) noexcept; +\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} + +\begin{itemdescr} +\pnum +\expects +\tcode{i < rank()} is \tcode{true}. + +\pnum +\returns +$D_\tcode{i}$. +\end{itemdescr} + +\rSec3[mdspan.extents.cmp]{Comparison operators} + +\indexlibrarymember{operator==}{extents}% +\begin{itemdecl} +template + friend constexpr bool operator==(const extents& lhs, + const extents& rhs) 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}. +\end{itemdescr} + +\rSec3[mdspan.extents.dextents]{Alias template \tcode{dextents}} + +\indexlibraryglobal{dextents}% +\begin{itemdecl} +template + using dextents = @\seebelow@; +\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} + +\rSec2[mdspan.layout]{Layout mapping} + +\rSec3[mdspan.layout.general]{General} + +\pnum +In subclauses \ref{mdspan.layout.reqmts} and \ref{mdspan.layout.policy.reqmts}: + +\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} + +\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} + +\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} + +\rSec3[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} + +\begin{itemdescr} +\pnum +\result +A type that is a specialization of \tcode{extents}. +\end{itemdescr} + +\begin{itemdecl} +typename M::index_type +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{typename M::extents_type::index_type}. +\end{itemdescr} + +\begin{itemdecl} +typename M::rank_type +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{typename M::extents_type::rank_type}. +\end{itemdescr} + +\begin{itemdecl} +typename M::layout_type +\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}. +\end{itemdescr} + +\begin{itemdecl} +m.extents() +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{const typename M::extents_type\&} +\end{itemdescr} + +\begin{itemdecl} +m(i...) +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{typename M::index_type} + +\pnum +\returns +A nonnegative integer +less than \tcode{numeric_limits::max()} and +less than or equal to \tcode{numeric_limits::max()}. +\end{itemdescr} + +\begin{itemdecl} +m(i...) == m(static_cast(i)...) +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{bool} + +\pnum +\returns +\tcode{true} +\end{itemdescr} + +\begin{itemdecl} +m.required_span_size() +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{typename M::index_type} + +\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} + +\begin{itemdecl} +m.is_unique() +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{bool} + +\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} +\end{itemdescr} + +\begin{itemdecl} +m.is_exhaustive() +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +\tcode{bool} + +\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} + +\begin{itemdescr} +\pnum +\result +\tcode{bool} + +\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} +\end{itemdescr} + +\begin{itemdecl} +m.stride(r) +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{m.is_strided()} is \tcode{true}. + +\pnum +\result +\tcode{typename M::index_type} + +\pnum +\returns +$s_r$ as defined in \tcode{m.is_strided()} above. +\end{itemdescr} + +\begin{itemdecl} +M::is_always_unique() +\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} +\end{itemdescr} + +\begin{itemdecl} +M::is_always_exhaustive() +\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_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} +M::is_always_strided() +\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_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} +\end{itemdescr} + +\rSec3[mdspan.layout.policy.reqmts]{Layout mapping policy requirements} + +\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}. + +\rSec3[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} + +\pnum +Each of \tcode{layout_left}, \tcode{layout_right}, and \tcode{layout_stride} +meets the layout mapping policy requirements and is a trivial type. + +\rSec3[mdspan.layout.left]{Class template \tcode{layout_left::mapping}} + +\rSec4[mdspan.layout.left.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. + +\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(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 + }; +} +\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}. + +\rSec4[mdspan.layout.left.cons]{Constructors} + +\indexlibraryctor{layout_left::mapping}% +\begin{itemdecl} +constexpr mapping(const extents_type& e) noexcept; +\end{itemdecl} + +\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}. + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{e}. +\end{itemdescr} + +\indexlibraryctor{layout_left::mapping}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + mapping(const mapping& other) 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}. + +\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{extents_type::rank() <= 1} is \tcode{true}, and +\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}\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(extents_type::rank() > 0) + mapping(const layout_stride::mapping& other); +\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{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 +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +\end{itemdescr} + +\rSec4[mdspan.layout.left.obs]{Observers} + +\indexlibrarymember{required_span_size}{layout_left::mapping}% +\begin{itemdecl} +constexpr index_type required_span_size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{extents().\exposid{fwd-prod-of-extents}(extents_type::rank())}. +\end{itemdescr} + +\indexlibrarymember{operator()}{layout_left::mapping}% +\begin{itemdecl} +template + constexpr index_type operator()(Indices... i) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\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 +\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_left::mapping}% +\begin{itemdecl} +constexpr index_type stride(rank_type i) const; +\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)}. +\end{itemdescr} + +\indexlibrarymember{operator==}{layout_left::mapping}% +\begin{itemdecl} +template + friend constexpr bool operator==(const mapping& x, const mapping& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{extents_type::rank() == OtherExtents::rank()} is \tcode{true}. \pnum -\tcode{ElementType} is required to be -a complete object type that is not an abstract class type. +\effects +Equivalent to: \tcode{return x.extents() == y.extents();} +\end{itemdescr} -\rSec3[span.cons]{Constructors, copy, and assignment} +\rSec3[mdspan.layout.right]{Class template \tcode{layout_right::mapping}} -\indexlibraryctor{span}% +\rSec4[mdspan.layout.right.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. + +\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(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 + }; +} +\end{codeblock} + +\pnum +If \tcode{Extents} is not a specialization of \tcode{extents}, +then the program is ill-formed. + +\pnum +\tcode{layout_right::mapping} is a trivially copyable type +that models \libconcept{regular} for each \tcode{E}. + +\rSec4[mdspan.layout.right.cons]{Constructors} + +\indexlibraryctor{layout_right::mapping}% \begin{itemdecl} -constexpr span() noexcept; +constexpr mapping(const extents_type& e) noexcept; +\end{itemdecl} + +\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}. + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{e}. +\end{itemdescr} + +\indexlibraryctor{layout_right::mapping}% +\begin{itemdecl} +template + constexpr explicit(!is_convertible_v) + mapping(const mapping& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{Extent == dynamic_extent || Extent == 0} is \tcode{true}. +\tcode{is_constructible_v} is \tcode{true}. \pnum -\ensures -\tcode{size() == 0 \&\& data() == nullptr}. +\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{span}% +\indexlibraryctor{layout_right::mapping}% \begin{itemdecl} -template - constexpr explicit(extent != dynamic_extent) span(It first, size_type count); +template + constexpr explicit(!is_convertible_v) + mapping(const layout_left::mapping& other) 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} +\tcode{extents_type::rank() <= 1} is \tcode{true}, and +\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}\iref{basic.fundamental}. + +\pnum +\effects +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +\end{itemdescr} + +\indexlibraryctor{layout_right::mapping}% +\begin{itemdecl} +template + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + \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}. +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{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 \effects -Initializes \tcode{data_} with \tcode{to_address(first)} and -\tcode{size_} with \tcode{count}. +Direct-non-list-initializes \exposid{extents_} with \tcode{other.extents()}. +\end{itemdescr} + +\rSec4[mdspan.layout.right.obs]{Observers} + +\indexlibrarymember{required_span_size}{layout_right::mapping}% +\begin{itemdecl} +index_type required_span_size() const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\throws -Nothing. +\returns +\tcode{extents().\exposid{fwd-prod-of-extents}(extents_type::rank())}. \end{itemdescr} -\indexlibraryctor{span}% +\indexlibrarymember{operator()}{layout_right::mapping}% \begin{itemdecl} -template - constexpr explicit(extent != dynamic_extent) span(It first, End last); +template + constexpr index_type operator()(Indices... i) const 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}. +\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 \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{extents_type::\exposid{index-cast}(i)} is +a multidimensional index in \exposid{extents_}\iref{mdspan.overview}. \pnum \effects -Initializes \tcode{data_} with \tcode{to_address(first)} and -\tcode{size_} with \tcode{last - first}. +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} +constexpr index_type stride(rank_type i) const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\throws -When and what \tcode{last - first} throws. +\constraints +\tcode{extents_type::rank() > 0} is \tcode{true}. + +\pnum +\expects +\tcode{i < extents_type::rank()} is \tcode{true}. + +\pnum +\returns +\tcode{extents().\exposid{rev-prod-of-extents}(i)}. \end{itemdescr} -\indexlibraryctor{span}% +\indexlibrarymember{operator==}{layout_right::mapping}% \begin{itemdecl} -template constexpr span(type_identity_t (&arr)[N]) noexcept; -template constexpr span(array& arr) noexcept; -template constexpr span(const array& arr) noexcept; +template + friend constexpr bool operator==(const mapping& x, const mapping& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints -Let \tcode{U} be \tcode{remove_pointer_t}. +\tcode{extents_type::rank() == OtherExtents::rank()} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return x.extents() == y.extents();} +\end{itemdescr} + +\rSec3[mdspan.layout.stride]{Class template \tcode{layout_stride::mapping}} + +\rSec4[mdspan.layout.stride.overview]{Overview} + +\pnum +\tcode{layout_stride} provides a layout mapping +where the strides are user-defined. + +\begin{codeblock} +namespace std { + template + 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_stride; + + private: + static constexpr rank_type @\exposid{rank_}@ = extents_type::rank(); // \expos + + public: + // \ref{mdspan.layout.stride.cons}, constructors + constexpr mapping() noexcept = default; + constexpr mapping(const mapping&) noexcept = default; + 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.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; + + 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 false; } + 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]; } + + template + friend constexpr bool operator==(const mapping&, const OtherMapping&) noexcept; + + private: + extents_type @\exposid{extents_}@{}; // \expos + array @\exposid{strides_}@{}; // \expos + }; +} +\end{codeblock} + +\pnum +If \tcode{Extents} is not a specialization of \tcode{extents}, +then the program is ill-formed. + +\pnum +\tcode{layout_stride::mapping} is a trivially copyable type +that models \libconcept{regular} for each \tcode{E}. + +\rSec4[mdspan.layout.stride.expo]{Exposition-only helpers} + +\pnum +Let \tcode{\exposid{REQUIRED-SPAN-SIZE}(e, strides)} be: \begin{itemize} -\item \tcode{extent == dynamic_extent || N == extent} is \tcode{true}, and -\item \tcode{is_convertible_v} is \tcode{true}. +\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 \tcode{strides[$r$]} +for all $r$ in the range $[0, \tcode{e.rank()})$. +\end{itemize} + +\pnum +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} -The intent is to allow only qualification conversions -of the array element type to \tcode{element_type}. +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} + +\rSec4[mdspan.layout.stride.cons]{Constructors} + +\indexlibraryctor{layout_stride::mapping}% +\begin{itemdecl} +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} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}, and +\item +\tcode{is_nothrow_constructible_v} is \tcode{true}. \end{itemize} \pnum -\effects -Constructs a \tcode{span} that is a view over the supplied array. +\expects +\begin{itemize} +\item +\tcode{s[$i$] > 0} is \tcode{true} +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} -\tcode{type_identity_t} affects class template argument deduction. +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{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_stride::mapping}% +\begin{itemdecl} +template + constexpr explicit(@\seebelow@) + mapping(const StridedLayoutMapping& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\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 +\tcode{StridedLayoutMapping} meets the layout mapping requirements\iref{mdspan.layout.policy.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} + +\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$)}. + +\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-mapping-of}@)) +\end{codeblock} +\end{itemdescr} +\rSec4[mdspan.layout.stride.obs]{Observers} + +\indexlibrarymember{required_span_size}{layout_stride::mapping}% +\begin{itemdecl} +constexpr index_type required_span_size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} \pnum -\ensures -\tcode{size() == N \&\& data() == data(arr)} is \tcode{true}. +\returns +\tcode{\exposid{REQUIRED-SPAN-SIZE}(extents(), \exposid{strides_})}. \end{itemdescr} -\indexlibraryctor{span}% +\indexlibrarymember{operator()}{layout_stride::mapping}% \begin{itemdecl} -template constexpr explicit(extent != dynamic_extent) span(R&& r); +template + constexpr index_type operator()(Indices... i) const noexcept; \end{itemdecl} \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} +\tcode{sizeof...(Indices) == \exposid{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 \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} +\tcode{extents_type::\exposid{index-cast}(i)} is +a multidimensional index in \exposid{extents_}\iref{mdspan.overview}. \pnum \effects -Initializes \tcode{data_} with \tcode{ranges::data(r)} and -\tcode{size_} with \tcode{ranges::size(r)}. - -\pnum -\throws -What and when \tcode{ranges::data(r)} and \tcode{ranges::size(r)} throw. +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} -\indexlibraryctor{span}% +\indexlibrarymember{is_exhaustive}{layout_stride::mapping}% \begin{itemdecl} -constexpr span(const span& other) noexcept = default; +constexpr bool is_exhaustive() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\ensures -\tcode{other.size() == size() \&\& other.data() == data()}. +\returns +\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} -\indexlibraryctor{span}% +\indexlibrarymember{operator==}{layout_stride::mapping}% \begin{itemdecl} -template - constexpr explicit(@\seebelow@) span(const span& s) noexcept; +template + friend constexpr bool operator==(const mapping& x, const OtherMapping& y) 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} +\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 \expects -If \tcode{extent} is not equal to \tcode{dynamic_extent}, -then \tcode{s.size()} is equal to \tcode{extent}. +\tcode{OtherMapping} meets the layout mapping requirements\iref{mdspan.layout.policy.reqmts}. \pnum -\effects -Constructs a \tcode{span} that is a view over the range -\range{s.data()}{s.data() + s.size()}. +\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} + +\rSec2[mdspan.accessor]{Accessor policy} + +\rSec3[mdspan.accessor.general]{General} \pnum -\ensures -\tcode{size() == s.size() \&\& data() == s.data()}. +An \defn{accessor policy} defines types and operations by which +a reference to a single object is created +from an abstract data handle to a number of such objects and an index. \pnum -\remarks -The expression inside \keyword{explicit} is equivalent to: -\begin{codeblock} -extent != dynamic_extent && OtherExtent == dynamic_extent -\end{codeblock} -\end{itemdescr} +A range of indices $[0, N)$ is an \defnadj{accessible}{range} of +a given data handle and an accessor +if, for each $i$ in the range, +the accessor policy's \tcode{access} function produces a valid reference to an object. + +\pnum +In subclause \ref{mdspan.accessor.reqmts}, + +\begin{itemize} +\item +\tcode{A} denotes an accessor policy. +\item +\tcode{a} denotes a value of type \tcode{A} or \tcode{const A}. +\item +\tcode{p} denotes a value of type \tcode{A::data_handle_type} or \tcode{const A::data_handle_type}. +\begin{note} +The type \tcode{A::data_handle_type} need not be dereferenceable. +\end{note} +\item +\tcode{n}, \tcode{i}, and \tcode{j} each denote values of type \tcode{size_t}. +\end{itemize} + +\rSec3[mdspan.accessor.reqmts]{Requirements} + +\pnum +A type \tcode{A} meets the accessor policy requirements if +\begin{itemize} +\item +\tcode{A} models \libconcept{copyable}, +\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{operator=}{span}% \begin{itemdecl} -constexpr span& operator=(const span& other) noexcept = default; +typename A::element_type \end{itemdecl} \begin{itemdescr} \pnum -\ensures -\tcode{size() == other.size() \&\& data() == other.data()}. +\result +A complete object type that is not an abstract class type. \end{itemdescr} -\rSec3[span.deduct]{Deduction guides} - -\indexlibrary{\idxcode{span}!deduction guide}% \begin{itemdecl} -template - span(It, EndOrSize) -> span>>; +typename A::data_handle_type \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{It} satisfies \libconcept{contiguous_iterator}. +\result +A type that models \libconcept{copyable}, and +for which \tcode{is_nothrow_move_constructible_v} is \tcode{true}, +\tcode{is_nothrow_move_assignable_v} is \tcode{true}, and +\tcode{is_nothrow_swappable_v} is \tcode{true}. +\begin{note} +The type of \tcode{data_handle_type} need not be \tcode{element_type*}. +\end{note} \end{itemdescr} -\indexlibrary{\idxcode{span}!deduction guide}% \begin{itemdecl} -template - span(R&&) -> span>>; +typename A::reference \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. +\result +A type that models +\tcode{\libconcept{common_reference_with}}. +\begin{note} +The type of \tcode{reference} need not be \tcode{element_type\&}. +\end{note} \end{itemdescr} -\rSec3[span.sub]{Subviews} +\begin{itemdecl} +typename A::offset_policy +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +A type \tcode{OP} such that: + +\begin{itemize} +\item +\tcode{OP} meets the accessor policy requirements, +\item +\tcode{\libconcept{constructible_from}} is modeled, and +\item +\tcode{is_same_v} is \tcode{true}. +\end{itemize} +\end{itemdescr} -\indexlibrarymember{span}{first}% \begin{itemdecl} -template constexpr span first() const; +a.access(p, i) \end{itemdecl} \begin{itemdescr} \pnum -\mandates -\tcode{Count <= Extent} is \tcode{true}. +\result +\tcode{A::reference} \pnum -\expects -\tcode{Count <= size()} is \tcode{true}. +\remarks +The expression is equality preserving. \pnum -\effects -Equivalent to: \tcode{return R\{data(), Count\};} -where \tcode{R} is the return type. +\begin{note} +Concrete accessor policies can impose preconditions for their \tcode{access} function. +However, they might not. +For example, an accessor where +\tcode{p} is \tcode{span} and +\tcode{access(p, i)} returns \tcode{p[i \% p.size()]} +does not need to impose a precondition on \tcode{i}. +\end{note} \end{itemdescr} -\indexlibrarymember{span}{last}% \begin{itemdecl} -template constexpr span last() const; +a.offset(p, i) \end{itemdecl} \begin{itemdescr} \pnum -\mandates -\tcode{Count <= Extent} is \tcode{true}. +\result +\tcode{A::offset_policy::data_handle_type} \pnum -\expects -\tcode{Count <= size()} is \tcode{true}. +\returns +\tcode{q} such that for \tcode{b} being \tcode{A::offset_policy(a)}, and +any integer \tcode{n} for which $[0, \tcode{n})$ is +an accessible range of \tcode{p} and \tcode{a}: +\begin{itemize} +\item +$[0, \tcode{n} - \tcode{i})$ is an accessible range of \tcode{q} and \tcode{b}; and +\item +\tcode{b.access(q, j)} provides access to +the same element as \tcode{a.access(p, i + j)}, +for every \tcode{j} in the range $[0, \tcode{n} - \tcode{i})$. +\end{itemize} \pnum -\effects -Equivalent to: \tcode{return R\{data() + (size() - Count), Count\};} -where \tcode{R} is the return type. +\remarks +The expression is equality-preserving. \end{itemdescr} -\indexlibrarymember{span}{subspan}% +\rSec3[mdspan.accessor.default]{Class template \tcode{default_accessor}} + +\rSec4[mdspan.accessor.default.overview]{Overview} + +\begin{codeblock} +namespace std { + template + struct default_accessor { + using offset_policy = default_accessor; + using element_type = ElementType; + using reference = ElementType&; + using data_handle_type = ElementType*; + + constexpr default_accessor() noexcept = default; + template + constexpr default_accessor(default_accessor) noexcept; + constexpr reference access(data_handle_type p, size_t i) const noexcept; + constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept; + }; +} +\end{codeblock} + +\pnum +\tcode{default_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{default_accessor} is +a trivially copyable type that models \libconcept{semiregular}. + +\pnum +$[0, n)$ is an accessible range for +an object \tcode{p} of type \tcode{data_handle_type} and +an object of type \tcode{default_accessor} +if and only if \range{p}{p + $n$} is a valid range. + +\rSec4[mdspan.accessor.default.members]{Members} + +\indexlibraryctor{default_accessor}% \begin{itemdecl} -template - constexpr span subspan() const; +template + constexpr default_accessor(default_accessor) noexcept {} \end{itemdecl} \begin{itemdescr} \pnum -\mandates -\begin{codeblock} -Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset) -\end{codeblock} +\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 -\expects -\begin{codeblock} -Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset) -\end{codeblock} -is \tcode{true}. +\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: -\begin{codeblock} -return span( - data() + Offset, Count != dynamic_extent ? Count : size() - Offset); -\end{codeblock} +Equivalent to: \tcode{return p + i;} +\end{itemdescr} + +\rSec2[mdspan.mdspan]{Class template \tcode{mdspan}} + +\rSec3[mdspan.mdspan.overview]{Overview} \pnum -\remarks -The second template argument of the returned \tcode{span} type is: +\tcode{mdspan} is a view of a multidimensional array of elements. + \begin{codeblock} -Count != dynamic_extent ? Count - : (Extent != dynamic_extent ? Extent - Offset - : dynamic_extent) +namespace std { + template + class mdspan { + public: + using extents_type = Extents; + using layout_type = LayoutPolicy; + using accessor_type = AccessorPolicy; + using mapping_type = typename layout_type::template mapping; + using element_type = ElementType; + using value_type = remove_cv_t; + 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 data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + static constexpr rank_type rank() noexcept { return extents_type::rank(); } + static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + static constexpr size_t static_extent(rank_type r) noexcept + { return extents_type::static_extent(r); } + constexpr index_type extent(rank_type r) const noexcept { return extents().extent(r); } + + // \ref{mdspan.mdspan.cons}, constructors + constexpr mdspan(); + constexpr mdspan(const mdspan& rhs) = default; + constexpr mdspan(mdspan&& rhs) = default; + + template + constexpr explicit mdspan(data_handle_type ptr, OtherIndexTypes... exts); + template + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, span exts); + template + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, const array& exts); + constexpr mdspan(data_handle_type p, const extents_type& ext); + constexpr mdspan(data_handle_type p, const mapping_type& m); + constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a); + + template + constexpr explicit(@\seebelow@) + mdspan(const mdspan& other); + + constexpr mdspan& operator=(const mdspan& rhs) = default; + constexpr mdspan& operator=(mdspan&& rhs) = default; + + // \ref{mdspan.mdspan.members}, members + template + constexpr reference operator[](OtherIndexTypes... indices) const; + template + constexpr reference operator[](span indices) const; + template + constexpr reference operator[](const array& indices) const; + + constexpr size_type size() const noexcept; + [[nodiscard]] constexpr bool empty() const noexcept; + + friend constexpr void swap(mdspan& x, mdspan& y) noexcept; + + constexpr const extents_type& extents() const noexcept { return @\exposid{map_}@.extents(); } + constexpr const data_handle_type& data_handle() const noexcept { return @\exposid{ptr_}@; } + constexpr const mapping_type& mapping() const noexcept { return @\exposid{map_}@; } + constexpr const accessor_type& accessor() const noexcept { return @\exposid{acc_}@; } + + static constexpr bool is_always_unique() + { return mapping_type::is_always_unique(); } + static constexpr bool is_always_exhaustive() + { return mapping_type::is_always_exhaustive(); } + static constexpr bool is_always_strided() + { return mapping_type::is_always_strided(); } + + constexpr bool is_unique() const + { return @\exposid{map_}@.is_unique(); } + constexpr bool is_exhaustive() const + { return @\exposid{map_}@.is_exhaustive(); } + constexpr bool is_strided() const + { return @\exposid{map_.}@is_strided(); } + constexpr index_type stride(rank_type r) const + { return @\exposid{map_}@.stride(r); } + + private: + accessor_type @\exposid{acc_}@; // \expos + mapping_type @\exposid{map_}@; // \expos + data_handle_type @\exposid{ptr_}@; // \expos + }; + + template + requires(is_array_v && rank_v == 1) + mdspan(CArray&) + -> mdspan, extents>>; + + template + requires(is_pointer_v>) + mdspan(Pointer&&) + -> mdspan>, extents>; + + template + requires((is_convertible_v && ...) && sizeof...(Integrals) > 0) + explicit mdspan(ElementType*, Integrals...) + -> mdspan>; + + template + mdspan(ElementType*, span) + -> mdspan>; + + template + mdspan(ElementType*, const array&) + -> mdspan>; + + template + mdspan(ElementType*, const extents&) + -> mdspan>; + + template + mdspan(ElementType*, const MappingType&) + -> mdspan; + + template + mdspan(const typename AccessorType::data_handle_type&, const MappingType&, + const AccessorType&) + -> mdspan; +} \end{codeblock} -\end{itemdescr} -\indexlibrarymember{span}{first}% +\pnum +\mandates +\begin{itemize} +\item +\tcode{ElementType} is a complete object type +that is neither an abstract class type nor an array type, +\item +\tcode{Extents} is a specialization of \tcode{extents}, and +\item +\tcode{is_same_v} +is \tcode{true}. +\end{itemize} + +\pnum +\tcode{LayoutPolicy} shall meet +the layout mapping policy requirements\iref{mdspan.layout.policy.reqmts}, and +\tcode{AccessorPolicy} shall meet +the accessor policy requirements\iref{mdspan.accessor.reqmts}. + +\pnum +Each specialization \tcode{MDS} of \tcode{mdspan} models \libconcept{copyable} and +\begin{itemize} +\item +\tcode{is_nothrow_move_constructible_v} is \tcode{true}, +\item +\tcode{is_nothrow_move_assignable_v} is \tcode{true}, and +\item +\tcode{is_nothrow_swappable_v} is \tcode{true}. +\end{itemize} + +\pnum +A specialization of \tcode{mdspan} is a trivially copyable type if +its \tcode{accessor_type}, \tcode{mapping_type}, and \tcode{data_handle_type} +are trivially copyable types. + +\rSec3[mdspan.mdspan.cons]{Constructors} + +\indexlibraryctor{mdspan}% \begin{itemdecl} -constexpr span first(size_type count) const; +constexpr mdspan(); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{rank_dynamic() > 0} is \tcode{true}. +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + \pnum \expects -\tcode{count <= size()} is \tcode{true}. +$[0, \tcode{\exposid{map_}.required_span_size()})$ is +an accessible range of \exposid{ptr_} and \exposid{acc_} +for the values of \exposid{map_} and \exposid{acc_} +after the invocation of this constructor. \pnum \effects -Equivalent to: \tcode{return \{data(), count\};} +Value-initializes \exposid{ptr_}, \exposid{map_}, and \exposid{acc_}. \end{itemdescr} -\indexlibrarymember{span}{last}% +\indexlibraryctor{mdspan}% \begin{itemdecl} -constexpr span last(size_type count) const; +template + constexpr explicit mdspan(data_handle_type p, OtherIndexTypes... exts); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{N} be \tcode{sizeof...(OtherIndexTypes)}. + +\pnum +\constraints +\begin{itemize} +\item +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, +\item +\tcode{(is_nothrow_constructible \&\& ...)} is \tcode{true}, +\item +\tcode{N == rank() || N == rank_dynamic()} is \tcode{true}, +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + \pnum \expects -\tcode{count <= size()} is \tcode{true}. +$[0, \tcode{\exposid{map_}.required_span_size()})$ is +an accessible range of \tcode{p} and \exposid{acc_} +for the values of \exposid{map_} and \exposid{acc_} +after the invocation of this constructor. \pnum \effects -Equivalent to: \tcode{return \{data() + (size() - count), count\};} +\begin{itemize} +\item +Direct-non-list-initializes \exposid{ptr_} with \tcode{std::move(p)}, +\item +direct-non-list-initializes \exposid{map_} with +\tcode{extents_type(static_cast(std::move(exts\brk{}))...)}, and +\item +value-initializes \exposid{acc_}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{span}{subspan}% +\indexlibraryctor{mdspan}% \begin{itemdecl} -constexpr span subspan( - size_type offset, size_type count = dynamic_extent) const; +template + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, span exts); +template + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, const array& exts); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}, +\item +\tcode{(is_nothrow_constructible \&\& ...)} is \tcode{true}, +\item +\tcode{N == rank() || N == rank_dynamic()} is \tcode{true}, +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} + \pnum \expects -\begin{codeblock} -offset <= size() && (count == dynamic_extent || count <= size() - offset) -\end{codeblock} -is \tcode{true}. +$[0, \tcode{\exposid{map_}.required_span_size()})$ is +an accessible range of \tcode{p} and \exposid{acc_} +for the values of \exposid{map_} and \exposid{acc_} +after the invocation of this constructor. \pnum \effects -Equivalent to: -\begin{codeblock} -return {data() + offset, count == dynamic_extent ? size() - offset : count}; -\end{codeblock} +\begin{itemize} +\item +Direct-non-list-initializes \exposid{ptr_} with \tcode{std::move(p)}, +\item +direct-non-list-initializes \exposid{map_} with \tcode{extents_type(exts)}, and +\item +value-initializes \exposid{acc_}. +\end{itemize} \end{itemdescr} -\rSec3[span.obs]{Observers} - -\indexlibrarymember{span}{size}% +\indexlibraryctor{mdspan}% \begin{itemdecl} -constexpr size_type size() const noexcept; +constexpr mdspan(data_handle_type p, const extents_type& ext); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return size_;} -\end{itemdescr} +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{is_default_constructible_v} is \tcode{true}. +\end{itemize} -\indexlibrarymember{span}{size_bytes}% -\begin{itemdecl} -constexpr size_type size_bytes() const noexcept; -\end{itemdecl} +\pnum +\expects +$[0, \tcode{\exposid{map_}.required_span_size()})$ is +an accessible range of \tcode{p} and \exposid{acc_} +for the values of \exposid{map_} and \exposid{acc_} +after the invocation of this constructor. -\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return size() * sizeof(element_type);} +\begin{itemize} +\item +Direct-non-list-initializes \exposid{ptr_} with \tcode{std::move(p)}, +\item +direct-non-list-initializes \exposid{map_} with \tcode{ext}, and +\item +value-initializes \exposid{acc_}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{span}{empty}% +\indexlibraryctor{mdspan}% \begin{itemdecl} -[[nodiscard]] constexpr bool empty() const noexcept; +constexpr mdspan(data_handle_type p, const mapping_type& m); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return size() == 0;} -\end{itemdescr} - -\rSec3[span.elem]{Element access} - -\indexlibrary{\idxcode{operator[]}!\idxcode{span}}% -\begin{itemdecl} -constexpr reference operator[](size_type idx) const; -\end{itemdecl} +\constraints +\tcode{is_default_constructible_v} is \tcode{true}. -\begin{itemdescr} \pnum \expects -\tcode{idx < size()} is \tcode{true}. +$[0, \tcode{m.required_span_size()})$ is +an accessible range of \tcode{p} and \exposid{acc_} +for the value of \exposid{acc_} after the invocation of this constructor. \pnum \effects -Equivalent to: \tcode{return *(data() + idx);} +\begin{itemize} +\item +Direct-non-list-initializes \exposid{ptr_} with \tcode{std::move(p)}, +\item +direct-non-list-initializes \exposid{map_} with \tcode{m}, and +\item +value-initializes \exposid{acc_}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{span}{front}% +\indexlibraryctor{mdspan}% \begin{itemdecl} -constexpr reference front() const; +constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{empty()} is \tcode{false}. +$[0, \tcode{m.required_span_size()})$ is +an accessible range of \tcode{p} and \tcode{a}. \pnum \effects -Equivalent to: \tcode{return *data();} +\begin{itemize} +\item +Direct-non-list-initializes \exposid{ptr_} with \tcode{std::move(p)}, +\item +direct-non-list-initializes \exposid{map_} with \tcode{m}, and +\item +direct-non-list-initializes \exposid{acc_} with \tcode{a}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{span}{back}% +\indexlibraryctor{mdspan}% \begin{itemdecl} -constexpr reference back() const; +template + constexpr explicit(@\seebelow@) + mdspan(const mdspan& other); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{empty()} is \tcode{false}. +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v\&>} +is \tcode{true}, and +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} \pnum -\effects -Equivalent to: \tcode{return *(data() + (size() - 1));} -\end{itemdescr} +\mandates +\begin{itemize} +\item +\tcode{is_constructible_v} is\newline \tcode{true}, and +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} -\indexlibrarymember{span}{data}% -\begin{itemdecl} -constexpr pointer data() const noexcept; -\end{itemdecl} +\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} -\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return data_;} +\begin{itemize} +\item +Direct-non-list-initializes \exposid{ptr_} with \tcode{other.\exposid{ptr_}}, +\item +direct-non-list-initializes \exposid{map_} with \tcode{other.\exposid{map_}}, and +\item +direct-non-list-initializes \exposid{acc_} with \tcode{other.\exposid{acc_}}. +\end{itemize} + +\pnum +\remarks +The expression inside \tcode{explicit} is equivalent to: +\begin{codeblock} +!is_convertible_v&, mapping_type> +|| !is_convertible_v +\end{codeblock} \end{itemdescr} -\rSec3[span.iterators]{Iterator support} +\rSec3[mdspan.mdspan.members]{Members} -\indexlibrarymember{iterator}{span}% +\indexlibrarymember{operator[]}{mdspan}% \begin{itemdecl} -using iterator = @\impdefx{type of \tcode{span::iterator}}@; +template + constexpr reference operator[](OtherIndexTypes... indices) const; \end{itemdecl} \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}. +\constraints +\begin{itemize} +\item +\tcode{(is_convertible_v \&\& ...)} is \tcode{true}, +\item +\tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}, and +\item +\tcode{sizeof...(OtherIndexTypes) == rank()} is \tcode{true}. +\end{itemize} \pnum -All requirements on container iterators\iref{container.requirements} apply to -\tcode{span::iterator} as well. -\end{itemdescr} +Let \tcode{I} be \tcode{extents_type::\exposid{index-cast}(std::move(indices))}. -\indexlibrarymember{span}{begin}% -\begin{itemdecl} -constexpr iterator begin() const noexcept; -\end{itemdecl} +\pnum +\expects +\tcode{I} is a multidimensional index in \tcode{extents()}. +\begin{note} +This implies that +\tcode{\exposid{map_}(I) < \exposid{map_}.required_span_size()} +is \tcode{true}. +\end{note} -\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()}. +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{acc_}@.access(@\exposid{ptr_}@, @\exposid{map_}@(static_cast(std::move(indices))...)); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{span}{end}% +\indexlibrarymember{operator[]}{mdspan}% \begin{itemdecl} -constexpr iterator end() const noexcept; +template + constexpr reference operator[](span indices) const; +template + constexpr reference operator[](const array& indices) const; \end{itemdecl} \begin{itemdescr} \pnum -\returns -An iterator which is the past-the-end value. -\end{itemdescr} - -\indexlibrarymember{span}{rbegin}% -\begin{itemdecl} -constexpr reverse_iterator rbegin() const noexcept; -\end{itemdecl} +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v} is \tcode{true}, and +\item +\tcode{is_nothrow_constructible_v} is \tcode{true}. +\end{itemize} -\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return reverse_iterator(end());} +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 operator[](as_const(indices[P])...); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{span}{rend}% +\indexlibrarymember{size}{mdspan}% \begin{itemdecl} -constexpr reverse_iterator rend() const noexcept; +constexpr size_type size() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return reverse_iterator(begin());} -\end{itemdescr} - +\expects +The size of the multidimensional index space \tcode{extents()} +is representable as a value of type \tcode{size_type}\iref{basic.fundamental}. -\rSec3[span.objectrep]{Views of object representation} +\pnum +\returns +\tcode{extents().\exposid{fwd-prod-of-extents}(rank())}. +\end{itemdescr} -\indexlibraryglobal{as_bytes}% +\indexlibrarymember{empty}{mdspan}% \begin{itemdecl} -template - span - as_bytes(span s) noexcept; +[[nodiscard]] constexpr bool empty() const noexcept; \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. +\returns +\tcode{true} +if the size of the multidimensional index space \tcode{extents()} is 0, +otherwise \tcode{false}. \end{itemdescr} -\indexlibraryglobal{as_writable_bytes}% +\indexlibrarymember{swap}{mdspan}% \begin{itemdecl} -template - span - as_writable_bytes(span s) noexcept; +friend constexpr void swap(mdspan& x, mdspan& y) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{is_const_v} is \tcode{false}. - \pnum \effects -Equivalent to: \tcode{return R\{reinterpret_cast(s.data()), s.size_bytes()\};} -where \tcode{R} is the return type. +Equivalent to: +\begin{codeblock} +swap(x.@\exposid{ptr_}@, y.@\exposid{ptr_}@); +swap(x.@\exposid{map_}@, y.@\exposid{map_}@); +swap(x.@\exposid{acc_}@, y.@\exposid{acc_}@); +\end{codeblock} \end{itemdescr} diff --git a/source/declarations.tex b/source/declarations.tex index 5cbc237f24..52b5847d64 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -770,12 +770,6 @@ The definition of a constexpr function shall satisfy the following requirements: \begin{itemize} -\item -its return type (if any) shall be a literal type; - -\item -each of its parameter types shall be a literal type; - \item it shall not be a coroutine\iref{dcl.fct.def.coroutine}; @@ -816,78 +810,6 @@ \end{codeblock} \end{example} -\pnum -\indextext{specifier!\idxcode{constexpr}!constructor}% -The definition of a constexpr constructor -whose \grammarterm{function-body} is not \tcode{= delete} -shall additionally satisfy the following requirements: -\begin{itemize} - -\item -for a non-delegating constructor, every constructor selected to initialize non-static -data members and base class subobjects shall be a constexpr constructor; - -\item -for a delegating constructor, the target constructor shall be a constexpr -constructor. -\end{itemize} - -\begin{example} -\begin{codeblock} -struct Length { - constexpr explicit Length(int i = 0) : val(i) { } -private: - int val; -}; -\end{codeblock} -\end{example} - -\pnum -The definition of a constexpr destructor -whose \grammarterm{function-body} is not \tcode{= delete} -shall additionally satisfy the following requirement: -\begin{itemize} -\item - for every subobject of class type or - (possibly multi-dimensional) array thereof, - that class type shall have a constexpr destructor. -\end{itemize} - -\pnum -For a constexpr function or constexpr constructor -that is neither defaulted nor a template, -if no argument values exist such that -an invocation of the function or constructor could be an evaluated subexpression of a core -constant expression\iref{expr.const}, or, -for a constructor, an evaluated subexpression of -the initialization full-expression of some constant-initialized object\iref{basic.start.static}, -the program is ill-formed, no diagnostic required. -\begin{example} -\begin{codeblock} -constexpr int f(bool b) - { return b ? throw 0 : 0; } // OK -constexpr int f() { return f(true); } // ill-formed, no diagnostic required - -struct B { - constexpr B(int x) : i(0) { } // \tcode{x} is unused - int i; -}; - -int global; - -struct D : B { - constexpr D() : B(global) { } // ill-formed, no diagnostic required - // lvalue-to-rvalue conversion on non-constant \tcode{global} -}; - -constexpr int f(int x) { - static int n = x; - return n + x; // ill-formed, no diagnostic required - // all calls reach the static variable declaration -} -\end{codeblock} -\end{example} - \pnum If the instantiated template specialization of a constexpr function template @@ -896,10 +818,7 @@ function, that specialization is still a constexpr function, even though a call to such a function cannot appear in a constant -expression. If no specialization of the template would satisfy the -requirements for a constexpr function -when considered as a non-template function, the template is -ill-formed, no diagnostic required. +expression. \pnum An invocation of a constexpr function in a given context @@ -919,6 +838,10 @@ This can indirectly cause calls to \tcode{std::is_constant_evaluated} within an invocation of the function to produce a different value. \end{note} +\begin{note} +It is possible to write a constexpr function for which +no invocation satisfies the requirements of a core constant expression. +\end{note} \pnum The \keyword{constexpr} and \keyword{consteval} specifiers have no @@ -1978,6 +1901,10 @@ the deduced type $\mathtt{T}'$ replacing \tcode{T} is determined using the rules for template argument deduction. +If the initialization is copy-list-initialization, +a declaration of \tcode{std::initializer_list} +shall precede\iref{basic.lookup.general} +the \grammarterm{placeholder-type-specifier}. Obtain \tcode{P} from \tcode{T} by replacing the occurrences of \opt{\grammarterm{type-constraint}} \keyword{auto} either with @@ -2036,6 +1963,8 @@ decltype(auto) x6d = { 1, 2 }; // error: \tcode{\{ 1, 2 \}} is not an expression auto *x7a = &i; // \tcode{decltype(x7a)} is \tcode{int*} decltype(auto)*x7d = &i; // error: declared type is not plain \tcode{decltype(auto)} +auto f1(int x) -> decltype((x)) { return (x); } // return type is \tcode{int\&} +auto f2(int x) -> decltype(auto) { return (x); } // return type is \tcode{int\&\&} \end{codeblock} \end{example} @@ -4086,8 +4015,8 @@ void h() { a = 2; { - int a = 3; - g(); // \tcode{g(f(::a))} + int a = 3; + g(); // \tcode{g(f(::a))} } } \end{codeblock} @@ -4119,7 +4048,7 @@ }; void C::f(int i = 3) {} // error: default argument already specified in class scope -void C::g(int i = 88, int j) {} // in this translation unit, \tcode{C::g} can be called with no argument +void C::g(int i = 88, int j) {} // in this translation unit, \tcode{C::g} can be called with no arguments \end{codeblock} \end{example} @@ -4583,7 +4512,7 @@ \end{codeblock} is not the declaration of an object of class \tcode{X}, -but the declaration of a function taking no argument and returning an +but the declaration of a function taking no arguments and returning an \tcode{X}. The form \tcode{()} @@ -5361,7 +5290,7 @@ \keyword{char16_t} array, \keyword{char32_t} array, or \keyword{wchar_t} array -can be initialized by +may be initialized by an ordinary string literal, UTF-8 string literal, UTF-16 string literal, @@ -5369,11 +5298,18 @@ wide string literal, respectively, or by an appropriately-typed \grammarterm{string-literal} enclosed in braces\iref{lex.string}. +Additionally, an array of \keyword{char} or +\tcode{\keyword{unsigned} \keyword{char}} +may be initialized by +a UTF-8 string literal, or by +such a string literal enclosed in braces. \indextext{initialization!character array}% Successive characters of the value of the \grammarterm{string-literal} -initialize the elements of the array. +initialize the elements of the array, +with an integral conversion\iref{conv.integral} +if necessary for the source and destination value. \begin{example} \begin{codeblock} char msg[] = "Syntax error on line %s\n"; @@ -5615,6 +5551,10 @@ \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} @@ -5717,10 +5657,12 @@ corresponding parameter to be a non-deduced context\iref{temp.deduct.call}. \end{note} The template -\tcode{std::initializer_list} is not predefined; if the header -\tcode{} is not imported or included prior to a use of -\tcode{std::initializer_list} --- even an implicit use in which the type is not -named\iref{dcl.spec.auto} --- the program is ill-formed. +\tcode{std::initializer_list} is not predefined; +if a standard library declaration\iref{initializer.list.syn,std.modules} +of \tcode{std::initializer_list} is not reachable from\iref{module.reach} +a use of \tcode{std::initializer_list} --- +even an implicit use in which the type is not named\iref{dcl.spec.auto} --- +the program is ill-formed. \pnum List-initialization of an object or reference of type \tcode{T} is defined as follows: @@ -6019,8 +5961,10 @@ \begin{itemize} \item from a floating-point type to an integer type, or -\item from \tcode{long double} to \tcode{double} or \tcode{float}, or from -\tcode{double} to \tcode{float}, except where the source is a constant expression and +\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 @@ -6211,46 +6155,55 @@ \end{itemize} \pnum -The type \tcode{T}$_1$ of an explicitly defaulted special member function \tcode{F} -is allowed to differ from the type \tcode{T}$_2$ it would have had -if it were implicitly declared, as follows: +An explicitly defaulted special member function $\tcode{F}_1$ +with type $\tcode{T}_1$ +is allowed to differ from +the corresponding special member function $\tcode{F}_2$ +with type $\tcode{T}_2$ +that would have been implicitly declared, as follows: \begin{itemize} \item - \tcode{T}$_1$ and \tcode{T}$_2$ may have differing \grammarterm{ref-qualifier}{s}; + $\tcode{T}_1$ and $\tcode{T}_2$ may have differing \grammarterm{ref-qualifier}{s}; +\item + if $\tcode{F}_2$ has an implicit object parameter of + type ``reference to \tcode{C}'', + $\tcode{F}_1$ may be an explicit object member function whose + explicit object parameter is of type ``reference to \tcode{C}'', + in which case $\tcode{T}_1$ would differ from $\tcode{T}_2$ + in that $\tcode{T}_1$ has an additional parameter; \item - \tcode{T}$_1$ and \tcode{T}$_2$ may have differing exception specifications; and + $\tcode{T}_1$ and $\tcode{T}_2$ may have differing exception specifications; and \item - if \tcode{T}$_2$ has a parameter of type \tcode{const C\&}, - the corresponding parameter of \tcode{T}$_1$ may be of type \tcode{C\&}. + if $\tcode{F}_2$ has a non-object parameter of type \tcode{const C\&}, + the corresponding non-object parameter of $\tcode{F}_1$ may be of + type \tcode{C\&}. \end{itemize} -If \tcode{T}$_1$ differs from \tcode{T}$_2$ in any other way, then: +If $\tcode{T}_1$ differs from $\tcode{T}_2$ in a way +other than as allowed by the preceding rules, then: \begin{itemize} \item - if \tcode{F} is an assignment operator, and - the return type of \tcode{T}$_1$ differs from - the return type of \tcode{T}$_2$ or - \tcode{T}$_1${'s} parameter type is not a reference, + if $\tcode{F}_1$ is an assignment operator, and + the return type of $\tcode{T}_1$ differs from + the return type of $\tcode{T}_2$ or + $\tcode{F}_1${'s} non-object parameter type is not a reference, the program is ill-formed; \item - otherwise, if \tcode{F} is explicitly defaulted on its first declaration, + otherwise, if $\tcode{F}_1$ is explicitly defaulted on its first declaration, it is defined as deleted; \item otherwise, the program is ill-formed. \end{itemize} \pnum -An explicitly-defaulted function that is not defined as deleted may be declared -\keyword{constexpr} or \keyword{consteval} only -if it is constexpr-compatible\iref{special,class.compare.default}. A function explicitly defaulted on its first declaration is implicitly inline\iref{dcl.inline}, -and is implicitly constexpr\iref{dcl.constexpr} if it is constexpr-compatible. +and is implicitly constexpr\iref{dcl.constexpr} +if it satisfies the requirements for a constexpr function. \pnum \begin{example} \begin{codeblock} struct S { - constexpr S() = default; // error: implicit \tcode{S()} is not \keyword{constexpr} S(int a = 0) = default; // error: default argument void operator=(const S&) = default; // error: non-matching return type ~S() noexcept(false) = default; // OK, despite mismatched exception specification @@ -6454,7 +6407,7 @@ \tcode{std::coroutine_traits::promise_type}, where \tcode{R} is the return type of the function, and -$\tcode{P}_1 \dotsc \tcode{P}_n$ are the sequence of types of the non-object function parameters, +$\tcode{P}_1 \dotsc \tcode{P}_n$ is the sequence of types of the non-object function parameters, preceded by the type of the object parameter\iref{dcl.fct} if the coroutine is a non-static member function. The promise type shall be a class type. @@ -6563,18 +6516,20 @@ The allocation function's name is looked up by searching for it in the scope of the promise type. \begin{itemize} \item -If any declarations are found, +If the search finds any declarations, overload resolution is performed on a function call created by assembling an -argument list. The first argument is the amount of space requested, and has -type \tcode{std::size_t}. -The lvalues $\tcode{p}_1 \dotsc \tcode{p}_n$ are the succeeding arguments. -\item -Otherwise, a search is performed in the global scope. -\end{itemize} +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. If no viable function is found\iref{over.match.viable}, overload resolution is performed again on a function call created by passing just -the amount of space required as an argument of type \tcode{std::size_t}. +the amount of space required as a prvalue of type \tcode{std::size_t}. +\item +If the search finds no declarations, a search is performed in the global scope. +Overload resolution is performed on a function call created by +passing the amount of space required as a prvalue of type \tcode{std::size_t}. +\end{itemize} \pnum If a search for the name \tcode{get_return_object_on_allocation_failure} @@ -8589,6 +8544,43 @@ \end{codeblock} \end{example} +\rSec2[dcl.attr.assume]{Assumption attribute} + +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 +shall have the form: +\begin{ncsimplebnf} +\terminal{(} conditional-expression \terminal{)} +\end{ncsimplebnf} +The expression is contextually converted to \tcode{bool}\iref{conv.general}. +The expression is not evaluated. +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. +\begin{note} +The expression is potentially evaluated\iref{basic.def.odr}. +The use of assumptions is intended to allow implementations +to analyze the form of the expression and +deduce information used to optimize the program. +Implementations are not required to deduce +any information from any particular assumption. +\end{note} +\begin{example} +\begin{codeblock} +int divide_by_32(int x) { + [[assume(x >= 0)]]; + return x/32; // The instructions produced for the division + // may omit handling of negative values. +} +int f(int y) { + [[assume(++y == 43)]]; // \tcode{y} is not incremented + return y; // statement may be replaced with \tcode{return 42;} +} +\end{codeblock} +\end{example} + \rSec2[dcl.attr.depend]{Carries dependency attribute}% \indextext{attribute!carries dependency} diff --git a/source/diagnostics.tex b/source/diagnostics.tex index b17a6e6fa0..bb70eb8ff3 100644 --- a/source/diagnostics.tex +++ b/source/diagnostics.tex @@ -1707,6 +1707,8 @@ \indexheader{stacktrace}% \begin{codeblock} +#include // see \ref{compare.syn} + namespace std { // \ref{stacktrace.entry}, class \tcode{stacktrace_entry} class stacktrace_entry; @@ -1757,7 +1759,7 @@ public: using native_handle_type = @\impdefx{\tcode{stacktrace_entry::native_handle_type}}@; - // \ref{stacktrace.entry.ctor}, constructors + // \ref{stacktrace.entry.cons}, constructors constexpr stacktrace_entry() noexcept; constexpr stacktrace_entry(const stacktrace_entry& other) noexcept; constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept; @@ -1790,7 +1792,7 @@ \libconcept{regular}\iref{concepts.object} and \tcode{\libconcept{three_way_comparable}}\iref{cmp.concept}. -\rSec3[stacktrace.entry.ctor]{Constructors} +\rSec3[stacktrace.entry.cons]{Constructors} \indexlibraryctor{stacktrace_entry}% \begin{itemdecl} @@ -1931,7 +1933,7 @@ using size_type = @\impdefx{type of \tcode{basic_stacktrace::size_type}}@; using allocator_type = Allocator; - // \ref{stacktrace.basic.ctor}, creation and assignment + // \ref{stacktrace.basic.cons}, creation and assignment static basic_stacktrace current(const allocator_type& alloc = allocator_type()) noexcept; static basic_stacktrace current(size_type skip, const allocator_type& alloc = allocator_type()) noexcept; @@ -2007,7 +2009,7 @@ are different from those required for a container. \end{itemize} -\rSec3[stacktrace.basic.ctor]{Creation and assignment} +\rSec3[stacktrace.basic.cons]{Creation and assignment} \indexlibrarymember{current}{basic_stacktrace}% \begin{itemdecl} @@ -2343,6 +2345,7 @@ \returns A string with a description of \tcode{f}. +\pnum \recommended The description should provide information about the contained evaluation, including information from diff --git a/source/exceptions.tex b/source/exceptions.tex index a436edfc57..15b2896a22 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -72,8 +72,8 @@ \indextext{\idxcode{switch}!and try block}% \indextext{\idxcode{goto}!and handler}% \indextext{\idxcode{switch}!and handler}% -A \tcode{goto} or \keyword{switch} statement shall not be used to transfer control -into a try block or into a handler. +The \grammarterm{compound-statement} of a try block or of a handler is a +control-flow-limited statement\iref{stmt.label}. \begin{example} \begin{codeblock} void f() { @@ -799,9 +799,7 @@ \end{codeblock} The call to \tcode{f} -is well-formed even though, when called, -\tcode{f} -might throw an exception. +is well-formed despite the possibility for it to throw an exception. \end{example} \pnum diff --git a/source/expressions.tex b/source/expressions.tex index 6710c39aeb..ec05f026da 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -186,6 +186,8 @@ \begin{note} An expression is an xvalue if it is: \begin{itemize} +\item a move-eligible \grammarterm{id-expression}\iref{expr.prim.id.unqual}, + \item the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type\iref{expr.call}, @@ -875,7 +877,7 @@ values of the bit-field; otherwise, it can be converted to \tcode{\keyword{unsigned} \keyword{int}} if \tcode{\keyword{unsigned} \keyword{int}} can represent all the values of the bit-field. If the bit-field is larger yet, no integral -promotion applies to it. If the bit-field has an enumerated type, it is +promotion applies to it. If the bit-field has enumeration type, it is treated as any other value of that type for promotion purposes. \pnum @@ -927,7 +929,13 @@ \pnum \indextext{conversion!floating-point}% A prvalue of floating-point type can be converted to a prvalue of -another floating-point type. If the source value can be exactly +another floating-point type +with a greater or equal conversion rank\iref{conv.rank}. +A prvalue of standard floating-point type can be converted to +a prvalue of another standard floating-point type. + +\pnum +If the source value can be exactly represented in the destination type, the result of the conversion is that exact representation. If the source value is between two adjacent destination values, the result of the conversion is an @@ -1112,24 +1120,36 @@ \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 If either operand is of type \tcode{\keyword{long} \keyword{double}}, the -other shall be converted to \tcode{\keyword{long} \keyword{double}}. - -\item Otherwise, if either operand is \keyword{double}, the other shall be -converted to \keyword{double}. - -\item Otherwise, if either operand is \keyword{float}, the other shall be -converted to \keyword{float}. - -\item Otherwise, the integral promotions\iref{conv.prom} shall be +\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. +\item +Otherwise, if one of the operands is of a non-floating-point type, +that operand is converted to the type of +the operand with the floating-point type. +\item +Otherwise, if the floating-point conversion ranks\iref{conv.rank} of +the types of the operands are ordered but not equal, +then the operand of the type with the lesser floating-point conversion rank +is converted to the type of the other operand. +\item +Otherwise, if the floating-point conversion ranks of the types of +the operands are equal, +then the operand with the lesser floating-point conversion subrank\iref{conv.rank} +is converted to the type of the other operand. +\item +Otherwise, the expression is ill-formed. +\end{itemize} +\item Otherwise, the integral promotions\iref{conv.prom} are performed on both operands. \begin{footnote} As a consequence, operands of type \keyword{bool}, \keyword{char8_t}, \keyword{char16_t}, -\keyword{char32_t}, \keyword{wchar_t}, or an enumerated type are converted +\keyword{char32_t}, \keyword{wchar_t}, or of enumeration type are converted to some integral type. \end{footnote} -Then the following rules shall be applied to the promoted operands: +Then the following rules are applied to the promoted operands: \begin{itemize} @@ -1138,20 +1158,20 @@ \item Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer -conversion rank shall be converted to the type of the operand with +conversion rank is converted to the type of the operand with greater rank. \item Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the -operand with signed integer type shall be converted to the type of the +operand with signed integer type is converted to the type of the operand with unsigned integer type. \item Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned -integer type, the operand with unsigned integer type shall be converted +integer type, the operand with unsigned integer type is converted to the type of the operand with signed integer type. -\item Otherwise, both operands shall be converted to the unsigned +\item Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type. \end{itemize} @@ -1453,10 +1473,11 @@ 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}, and: +then let $E$ be the innermost such \grammarterm{lambda-expression}. \begin{itemize} \item -If $P$ is in $E$'s function parameter scope +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 type of the expression is the type of a class member access expression\iref{expr.ref} @@ -1468,11 +1489,11 @@ the type of such an identifier will typically be \keyword{const} qualified. \end{note} \item -Otherwise (if $P$ either precedes $E$'s function parameter scope or +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 program is ill-formed. +the type of the expression is the type of the result. \end{itemize} -Otherwise, the type of the expression is the type of the result. \begin{note} If the entity is a template parameter object for a template parameter of type \tcode{T}\iref{temp.param}, @@ -1482,15 +1503,17 @@ The type will be adjusted as described in \ref{expr.type} if it is cv-qualified or is a reference type. \end{note} -The expression is an lvalue +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 -template parameter object +template parameter object; and a prvalue otherwise\iref{basic.lval}; it is a bit-field if the identifier designates a bit-field. \begin{example} \begin{codeblock} void f() { float x, &r = x; + [=]() -> decltype((x)) { // lambda returns \tcode{float const\&} because this lambda is not \tcode{mutable} and // \tcode{x} is an lvalue decltype(x) y1; // \tcode{y1} has type \tcode{float} @@ -1500,20 +1523,49 @@ return y2; }; - [=]{}; // error: \tcode{x} refers to local entity but precedes the - // lambda's function parameter scope - [=](decltype((x)) y){}; // error: \tcode{x} refers to local entity but is in the lambda's - // \grammarterm{parameter-declaration-clause} - [=]{ - []{}; // OK, \tcode{x} is in the outer lambda's function parameter scope - [](decltype((x)) y){}; // OK, lambda takes a parameter of type \tcode{float const\&} - [x=1](decltype((x)) z){}; // error: \tcode{x} refers to \grammarterm{init-capture} but is in the lambda's - // \grammarterm{parameter-declaration-clause} + [=](decltype((x)) y) { + decltype((x)) z = x; // OK, \tcode{y} has type \tcode{float\&}, \tcode{z} has type \tcode{float const\&} + }; + + [=] { + [](decltype((x)) y) {}; // OK, lambda takes a parameter of type \tcode{float const\&} + + [x=1](decltype((x)) y) { + decltype((x)) z = x; // OK, \tcode{y} has type \tcode{int\&}, \tcode{z} has type \tcode{int const\&} + }; }; } \end{codeblock} \end{example} +\pnum +An \defnadj{implicitly movable}{entity} is +a variable of automatic storage duration +that is either a non-volatile object or +an rvalue reference to a non-volatile object type. +In the following contexts, +an \grammarterm{id-expression} is \defn{move-eligible}: +\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}. +\end{itemize} + \rSec3[expr.prim.id.qual]{Qualified names} \indextext{operator!scope resolution}% @@ -1694,7 +1746,8 @@ \nontermdef{lambda-specifier}\br \keyword{consteval}\br \keyword{constexpr}\br - \keyword{mutable} + \keyword{mutable}\br + \keyword{static} \end{bnf} \begin{bnf} @@ -1745,7 +1798,11 @@ If the \grammarterm{lambda-declarator} contains an explicit object parameter\iref{dcl.fct}, then no \grammarterm{lambda-specifier} in the \grammarterm{lambda-specifier-seq} -shall be \keyword{mutable}. +shall be \keyword{mutable} or \keyword{static}. +The \grammarterm{lambda-specifier-seq} shall not contain +both \keyword{mutable} and \keyword{static}. +If the \grammarterm{lambda-specifier-seq} contains \keyword{static}, +there shall be no \grammarterm{lambda-capture}. \begin{note} The trailing \grammarterm{requires-clause} is described in \ref{dcl.decl}. \end{note} @@ -1757,15 +1814,17 @@ at the start of the \grammarterm{lambda-declarator}. If the \grammarterm{lambda-declarator} does not include a \grammarterm{trailing-return-type}, -the lambda return type is \keyword{auto}, -which is deduced from \keyword{return} statements +it is considered to be \tcode{-> \keyword{auto}}. +\begin{note} +In that case, the return type is deduced from \keyword{return} statements as described in \ref{dcl.spec.auto}. +\end{note} \begin{example} \begin{codeblock} auto x1 = [](int i) { return i; }; // OK, return type is \tcode{int} auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from \grammarterm{braced-init-list} int j; -auto x3 = []()->auto&& { return j; }; // OK, return type is \tcode{int\&} +auto x3 = [&]()->auto&& { return j; }; // OK, return type is \tcode{int\&} \end{codeblock} \end{example} @@ -1890,7 +1949,13 @@ \end{example} \pnum -The function call operator or operator template is declared +The function call operator or operator template is +a static member function or static member function template\iref{class.static.mfct} +if the \grammarterm{lambda-expression}'s +\grammarterm{parameter-declaration-clause} is followed by \keyword{static}. +Otherwise, it is +a non-static member function or member function template\iref{class.mfct.non.static} +that is declared \keyword{const}\iref{class.mfct.non.static} if and only if the \grammarterm{lambda-expression}'s \grammarterm{parameter-declaration-clause} is not followed by \keyword{mutable} and @@ -1986,7 +2051,10 @@ The conversion is to ``pointer to \keyword{noexcept} function'' if the function call operator has a non-throwing exception specification. -The value returned by this conversion function +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. +Otherwise, the value returned by this conversion function is the address of 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. @@ -2057,7 +2125,12 @@ \end{example} \pnum -The value returned by any given specialization of this conversion function +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. +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 effect as invoking the generic lambda's corresponding function call operator template specialization on a default-constructed instance of the closure type. @@ -2240,22 +2313,27 @@ is said to be \defn{explicitly captured}. \pnum -If an \grammarterm{identifier} in a \grammarterm{simple-capture} appears +If an \grammarterm{identifier} in a \grammarterm{capture} appears as the \grammarterm{declarator-id} of a parameter of -the \grammarterm{lambda-declarator}{'s} \grammarterm{parameter-declaration-clause}, +the \grammarterm{lambda-declarator}'s \grammarterm{parameter-declaration-clause} +or as the name of a template parameter of +the \grammarterm{lambda-expression}'s \grammarterm{template-parameter-list}, the program is ill-formed. \begin{example} \begin{codeblock} void f() { int x = 0; - auto g = [x](int x) { return 0; }; // error: parameter and \grammarterm{simple-capture} have the same name + auto g = [x](int x) { return 0; }; // error: parameter and \grammarterm{capture} have the same name + auto h = [y = 0](y) { return 0; }; // error: template parameter and \grammarterm{capture} + // have the same name } \end{codeblock} \end{example} \pnum -An \grammarterm{init-capture} inhabits the function parameter scope of -the \grammarterm{lambda-expression}'s \grammarterm{parameter-declaration-clause}. +An \grammarterm{init-capture} inhabits +the lambda scope\iref{basic.scope.lambda} +of the \grammarterm{lambda-expression}. An \grammarterm{init-capture} without ellipsis behaves as if it declares and explicitly captures a variable of the form ``\keyword{auto} \grammarterm{init-capture} \tcode{;}'', except that: @@ -3055,9 +3133,17 @@ A \defnadj{subscript}{expression} is a postfix expression followed by square brackets containing a possibly empty, comma-separated list of \grammarterm{initializer-clause}s -which constitute the arguments to the subscript operator. -The \grammarterm{postfix-expression} is sequenced before -each expression in the \grammarterm{expression-list}. +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 +each expression in the \grammarterm{expression-list} and also before +any default argument. +The initialization of a non-object parameter of +a subscript operator function \tcode{S}\iref{over.sub}, +including every associated value computation and side effect, +is indeterminately sequenced with respect to that of +any other non-object parameter of \tcode{S}. \pnum With the built-in subscript operator, @@ -3476,7 +3562,7 @@ If the object expression is of scalar type, \tcode{E2} shall name the pseudo-destructor of that same type (ignoring cv-qualifications) and -\tcode{E1.E2} is an lvalue of type ``function of () returning \keyword{void}''. +\tcode{E1.E2} is a prvalue of type ``function of () returning \keyword{void}''. \begin{note} This value can only be used for a notional function call\iref{expr.prim.id.dtor}. @@ -3559,8 +3645,8 @@ \end{itemize} \pnum -If \tcode{E2} is a non-static data member or a non-static member -function, the program is ill-formed if the class of which \tcode{E2} is +If \tcode{E2} is a non-static member, +the program is ill-formed if the class of which \tcode{E2} is directly a member is an ambiguous base\iref{class.member.lookup} of the naming class\iref{class.access.base} of \tcode{E2}. \begin{note} @@ -3568,6 +3654,24 @@ of the object expression; see~\ref{class.access.base}. \end{note} +\pnum +If \tcode{E2} is a non-static member and +the result of \tcode{E1} is an object whose type +is not similar\iref{conv.qual} to the type of \tcode{E1}, +the behavior is undefined. +\begin{example} +\begin{codeblock} +struct A { int i; }; +struct B { int j; }; +struct D : A, B {}; +void f() { + D d; + static_cast(d).j; // OK, object expression designates the \tcode{B} subobject of \tcode{d} + reinterpret_cast(d).j; // undefined behavior +} +\end{codeblock} +\end{example} + \rSec3[expr.post.incr]{Increment and decrement} \pnum @@ -3839,9 +3943,10 @@ \end{example} \pnum -If the header \libheaderref{typeinfo} -is not imported or included prior -to a use of \keyword{typeid}, the program is ill-formed. +The type \tcode{std::type_info}\iref{type.info} is not predefined; +if a standard library declaration\iref{typeinfo.syn,std.modules} of +\tcode{std::type_info} does not precede\iref{basic.lookup.general} +a \tcode{typeid} expression, the program is ill-formed. \pnum \begin{note} @@ -4018,6 +4123,17 @@ underlying type of the enumeration\iref{conv.fpint}, and subsequently to the enumeration type. +\pnum +A prvalue of floating-point type can be explicitly converted to +any other floating-point type. +If the source value can be exactly represented in the destination type, +the result of the conversion has that exact representation. +If the source value is between two adjacent destination values, +the result of the conversion is +an \impldef{result of inexact floating-point conversion} choice of +either of those values. +Otherwise, the behavior is undefined. + \pnum \indextext{cast!base class}% \indextext{cast!derived class}% @@ -4078,7 +4194,7 @@ \tcode{A} does not satisfy the alignment requirement of \tcode{T}, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an object \placeholder{a}, -and there is an object \placeholder{b} of type \tcode{T} (ignoring cv-qualification) +and there is an object \placeholder{b} of type similar to \tcode{T} that is pointer-interconvertible\iref{basic.compound} with \placeholder{a}, the result is a pointer to \placeholder{b}. Otherwise, the pointer value is unchanged by the conversion. @@ -4781,7 +4897,7 @@ my_future h(); my_future g() { - std::cout << "just about go to sleep...\n"; + std::cout << "just about to go to sleep...\n"; co_await 10ms; std::cout << "resumed\n"; co_await h(); @@ -5937,10 +6053,12 @@ \pnum Abbreviating \grammarterm{pm-expression}\tcode{.*}\grammarterm{cast-expression} as \tcode{E1.*E2}, \tcode{E1} is called the \defn{object expression}. -If the dynamic type of \tcode{E1} does not +If the result of \tcode{E1} is an object +whose type is not similar to the type of \tcode{E1}, or +whose most derived object does not contain the member to which \tcode{E2} refers, the behavior is undefined. -Otherwise, the expression \tcode{E1} is sequenced before the expression \tcode{E2}. +The expression \tcode{E1} is sequenced before the expression \tcode{E2}. \pnum The restrictions on cv-qualification, and the manner in which @@ -5958,9 +6076,9 @@ }; void f() { -const S cs; -int S::* pm = &S::i; // \tcode{pm} refers to \keyword{mutable} member \tcode{S::i} -cs.*pm = 88; // error: \tcode{cs} is a const object + const S cs; + int S::* pm = &S::i; // \tcode{pm} refers to \keyword{mutable} member \tcode{S::i} + cs.*pm = 88; // error: \tcode{cs} is a const object } \end{codeblock} \end{note} @@ -6316,12 +6434,13 @@ \tcode{std::weak_ordering}, and \tcode{std::partial_ordering}) are not predefined; -if the header \libheaderref{compare} -is not imported or included prior to a use of such a class type -- +if a standard library declaration\iref{compare.syn,std.modules} +of such a class type does not precede\iref{basic.lookup.general} +a use of that type --- even an implicit use in which the type is not named (e.g., via the \keyword{auto} specifier\iref{dcl.spec.auto} in a defaulted three-way comparison\iref{class.spaceship} -or use of the built-in operator) -- the program is ill-formed. +or use of the built-in operator) --- the program is ill-formed. \rSec2[expr.rel]{Relational operators}% \indextext{expression!relational operators}% @@ -6586,7 +6705,7 @@ of the base-2 representation of the result \tcode{r} is 1 if both $\tcode{x}_i$ and $\tcode{y}_i$ are 1, and 0 otherwise. \begin{note} -The result is the bitwise \logop{AND} function of the operands. +The result is the bitwise \logop{and} function of the operands. \end{note} \rSec2[expr.xor]{Bitwise exclusive OR operator}% @@ -6609,10 +6728,10 @@ of the converted operands \tcode{x} and \tcode{y}, the coefficient $\tcode{r}_i$ of the base-2 representation of the result \tcode{r} -is 1 if either (but not both) of $\tcode{x}_i$ and $\tcode{y}_i$ are 1, +is 1 if either (but not both) of $\tcode{x}_i$ and $\tcode{y}_i$ is 1, and 0 otherwise. \begin{note} -The result is the bitwise exclusive \logop{OR} function of the operands. +The result is the bitwise exclusive \logop{or} function of the operands. \end{note} \rSec2[expr.or]{Bitwise inclusive OR operator}% @@ -6635,9 +6754,9 @@ of the converted operands \tcode{x} and \tcode{y}, the coefficient $\tcode{r}_i$ of the base-2 representation of the result \tcode{r} -is 1 if at least one of $\tcode{x}_i$ and $\tcode{y}_i$ are 1, and 0 otherwise. +is 1 if at least one of $\tcode{x}_i$ and $\tcode{y}_i$ is 1, and 0 otherwise. \begin{note} -The result is the bitwise inclusive \logop{OR} function of the operands. +The result is the bitwise inclusive \logop{or} function of the operands. \end{note} \rSec2[expr.log.and]{Logical AND operator}% @@ -6898,10 +7017,10 @@ }; my_generator> g1() { - for (int i = i; i < 10; ++i) co_yield {i,i}; + for (int i = 0; i < 10; ++i) co_yield {i,i}; } my_generator> g2() { - for (int i = i; i < 10; ++i) co_yield make_pair(i,i); + for (int i = 0; i < 10; ++i) co_yield make_pair(i,i); } auto f(int x = co_yield 5); // error: \grammarterm{yield-expression} outside of function suspension context @@ -7037,7 +7156,7 @@ \impldefplain{value of bit-field that cannot represent!assigned value}. \pnum -A simple assignment whose left operand is of +An assignment whose left operand is of a volatile-qualified type is deprecated\iref{depr.volatile.type} unless the (possibly parenthesized) assignment is a discarded-value expression or an unevaluated operand\iref{term.unevaluated.operand}. @@ -7047,7 +7166,9 @@ is equivalent to \tcode{E1 = E1 \placeholder{op} E2} except that \tcode{E1} is evaluated only once. Such expressions are deprecated -if \tcode{E1} has volatile-qualified type; see~\ref{depr.volatile.type}. +if \tcode{E1} has volatile-qualified type +and \placeholder{op} is not one of the bitwise operators +\tcode{|}, \tcode{\&}, \tcode{\^}; see~\ref{depr.volatile.type}. For \tcode{+=} and \tcode{-=}, \tcode{E1} shall either have arithmetic type or be a pointer to a possibly cv-qualified completely-defined object type. In all other @@ -7207,9 +7328,15 @@ machine\iref{intro.execution}, would evaluate one of the following: \begin{itemize} \item -\keyword{this}\iref{expr.prim.this}, except in a constexpr -function\iref{dcl.constexpr} that is being evaluated as part -of $E$; +\keyword{this}\iref{expr.prim.this}, except +\begin{itemize} +\item +in a constexpr function\iref{dcl.constexpr} +that is being evaluated as part of $E$ or +\item +when appearing as the \grammarterm{postfix-expression} of +an implicit or explicit class member access expression\iref{expr.ref}; +\end{itemize} \item a control flow that passes through @@ -7234,11 +7361,7 @@ \item an invocation of a virtual function\iref{class.virtual} -for an object unless - \begin{itemize} - \item the object is usable in constant expressions or - \item its lifetime began within the evaluation of $E$; - \end{itemize} +for an object whose dynamic type is constexpr-unknown; \item an expression that would exceed the implementation-defined @@ -7246,7 +7369,8 @@ \item an operation that would have undefined behavior -as specified in \ref{intro} through \ref{cpp}; +as specified in \ref{intro} through \ref{cpp}, +excluding \ref{dcl.attr.assume}; \begin{footnote} This includes, for example, signed integer overflow\iref{expr.pre}, certain @@ -7282,18 +7406,6 @@ for a union whose active member (if any) is mutable, unless the lifetime of the union object began within the evaluation of $E$; -\item -an \grammarterm{id-expression} that refers to a variable or -data member of reference type -unless the reference has a preceding initialization and either -\begin{itemize} - \item - it is usable in constant expressions or - - \item - its lifetime began within the evaluation of $E$; -\end{itemize} - \item in a \grammarterm{lambda-expression}, a reference to \keyword{this} or to a variable with @@ -7385,7 +7497,10 @@ a \grammarterm{throw-expression}\iref{expr.throw}; \item -a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or \keyword{typeid}\iref{expr.typeid} expression +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; \item @@ -7402,12 +7517,28 @@ a \keyword{goto} statement\iref{stmt.goto}. \end{itemize} -If $E$ satisfies the constraints of a core constant expression, but -evaluation of $E$ would evaluate an operation that has undefined behavior -as specified in \ref{library} through \ref{\lastlibchapter}, or -an invocation of the \tcode{va_start} macro\iref{cstdarg.syn}, -it is unspecified whether $E$ is a core constant expression. - +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 +\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} +\end{itemize} \begin{example} \begin{codeblock} int x; // not constant @@ -7467,6 +7598,71 @@ the evaluation of the underlying constructor call disqualifies $E$ from being a core constant expression. +\pnum +During the evaluation of an expression $E$ as a core constant expression, +all \grammarterm{id-expression}s and uses of \tcode{*\keyword{this}} +that refer to an object or reference +whose lifetime did not begin with the evaluation of $E$ +are treated as referring to a specific instance of that object or reference +whose lifetime and that of all subobjects (including all union members) +includes the entire constant evaluation. +For such an object that is not usable in constant expressions, +the dynamic type of the object is \defn{constexpr-unknown}. +For such a reference that is not usable in constant expressions, +the reference is treated as binding to +an unspecified object of the referenced type +whose lifetime and that of all subobjects includes +the entire constant evaluation and whose dynamic type is constexpr-unknown. +\begin{example} +\begin{codeblock} +template +constexpr size_t array_size(T (&)[N]) { + return N; +} + +void use_array(int const (&gold_medal_mel)[2]) { + constexpr auto gold = array_size(gold_medal_mel); // OK +} + +constexpr auto olympic_mile() { + const int ledecky = 1500; + return []{ return ledecky; }; +} +static_assert(olympic_mile()() == 1500); // OK + +struct Swim { + constexpr int phelps() { return 28; } + virtual constexpr int lochte() { return 12; } + int coughlin = 12; +}; + +constexpr int how_many(Swim& swam) { + Swim* p = &swam; + return (p + 1 - 1)->phelps(); +} + +void splash(Swim& swam) { + static_assert(swam.phelps() == 28); // OK + static_assert((&swam)->phelps() == 28); // OK + Swim* pswam = &swam; + static_assert(pswam->phelps() == 28); // error: lvalue-to-rvalue conversion on a pointer + // not usable in constant expressions + static_assert(how_many(swam) == 28); // OK + static_assert(Swim().lochte() == 12); // OK + static_assert(swam.lochte() == 12); // error: invoking virtual function on reference + // with constexpr-unknown dynamic type + static_assert(swam.coughlin == 12); // error: lvalue-to-rvalue conversion on an object + // not usable in constant expressions +} + +extern Swim dc; +extern Swim& trident; + +constexpr auto& sandeno = typeid(dc); // OK, can only be \tcode{typeid(Swim)} +constexpr auto& gallagher = typeid(trident); // error: constexpr-unknown dynamic type +\end{codeblock} +\end{example} + \pnum An object \tcode{a} is said to have \defnadj{constant}{destruction} if: \begin{itemize} @@ -7580,6 +7776,11 @@ 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 +is not a constant expression. +\end{note} \begin{example} \begin{codeblock} consteval int f() { return 42; } diff --git a/source/future.tex b/source/future.tex index 17bd08d0ea..093dba383e 100644 --- a/source/future.tex +++ b/source/future.tex @@ -106,6 +106,7 @@ tail = brachiosaur = neck; // deprecated brachiosaur += neck; // deprecated brachiosaur = brachiosaur + neck; // OK +brachiosaur |= neck; // OK, bitwise compound expression \end{codeblock} \end{example} @@ -1432,7 +1433,7 @@ to \exposid{default-alignment}. \pnum -The member typedef \tcode{type} is a trivial standard-layout type +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}. @@ -1472,7 +1473,7 @@ is a complete object type. \pnum -The member typedef \tcode{type} is a trivial standard-layout type +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}. @@ -1488,17 +1489,17 @@ \begin{codeblock} namespace std { - template class tuple_size; - template class tuple_size; + template struct tuple_size; + template struct tuple_size; - template class tuple_element; - template class tuple_element; + template struct tuple_element; + template struct tuple_element; } \end{codeblock} \begin{itemdecl} -template class tuple_size; -template class tuple_size; +template struct tuple_size; +template struct tuple_size; \end{itemdecl} \begin{itemdescr} @@ -1526,8 +1527,8 @@ \end{itemdescr} \begin{itemdecl} -template class tuple_element; -template class tuple_element; +template struct tuple_element; +template struct tuple_element; \end{itemdecl} \begin{itemdescr} @@ -1567,8 +1568,8 @@ \end{codeblock} \begin{itemdecl} -template class variant_size; -template class variant_size; +template struct variant_size; +template struct variant_size; \end{itemdecl} \begin{itemdescr} @@ -1581,8 +1582,8 @@ \end{itemdescr} \begin{itemdecl} -template class variant_alternative; -template class variant_alternative; +template struct variant_alternative; +template struct variant_alternative; \end{itemdecl} \begin{itemdescr} @@ -2638,8 +2639,6 @@ void atomic_init(atomic*, typename atomic::value_type) noexcept; #define ATOMIC_VAR_INIT(value) @\seebelow@ - - #define ATOMIC_FLAG_INIT @\seebelow@ } \end{codeblock} @@ -2708,25 +2707,3 @@ \end{codeblock} \end{example} \end{itemdescr} - -\rSec2[depr.atomics.flag]{Flag type and operations} - -\indexlibraryglobal{ATOMIC_FLAG_INIT}% -\begin{itemdecl} -#define ATOMIC_FLAG_INIT @\seebelow@ -\end{itemdecl} - -\begin{itemdescr} -\pnum -\remarks -The macro \tcode{ATOMIC_FLAG_INIT} is defined in such a way that -it can be used to initialize an object of type \tcode{atomic_flag} -to the clear state. -The macro can be used in the form: -\begin{codeblock} -atomic_flag guard = ATOMIC_FLAG_INIT; -\end{codeblock} -It is unspecified whether the macro can be used -in other initialization contexts. -For a complete static-duration object, that initialization shall be static. -\end{itemdescr} diff --git a/source/intro.tex b/source/intro.tex index 9200f81357..cce294040a 100644 --- a/source/intro.tex +++ b/source/intro.tex @@ -33,6 +33,7 @@ For undated references, the latest edition of the referenced document (including any amendments) applies. \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} @@ -58,9 +59,12 @@ \end{footnote} \doccite{Information technology --- Universal Multiple-Octet Coded Character Set (UCS)} +\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} +% Other international standards. \item Ecma International, \doccite{ECMAScript \begin{footnote} ECMAScript\textregistered\ is a registered trademark of Ecma @@ -840,12 +844,16 @@ \pnum Two kinds of implementations are defined: a \defnadj{hosted}{implementation} and a -\defnadj{freestanding}{implementation}. For a hosted implementation, this -document defines the set of available libraries. A freestanding +\defnadj{freestanding}{implementation}. +A freestanding implementation is one in which execution may take place without the benefit of -an operating system, and has an \impldef{required libraries for freestanding -implementation} set of libraries that includes certain language-support -libraries\iref{compliance}. +an operating system. +A hosted implementation +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 +the subset of the library facilities described in \ref{compliance}. \pnum A conforming implementation may have extensions (including diff --git a/source/iostreams.tex b/source/iostreams.tex index bb586b70d6..851476a378 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -778,6 +778,7 @@ static constexpr openmode ate = @\unspec@; static constexpr openmode binary = @\unspec@; static constexpr openmode in = @\unspec@; + static constexpr openmode noreplace = @\unspec@; static constexpr openmode out = @\unspec@; static constexpr openmode trunc = @\unspec@; @@ -1070,6 +1071,8 @@ perform input and output in binary mode (as opposed to text mode) \\ \tcode{in} & open for input \\ +\tcode{noreplace} & + open in exclusive mode \\ \tcode{out} & open for output \\ \tcode{trunc} & @@ -1455,7 +1458,7 @@ \tcode{iarray} as necessary to include the element \tcode{iarray[idx]}. Each newly allocated element of the array is initialized to zero. -The reference returned is invalid after any other operations on the +The reference returned is invalid after any other operation on the object. \begin{footnote} An implementation is free to implement both the integer @@ -1512,7 +1515,7 @@ \tcode{parray[idx]}. Each newly allocated element of the array is initialized to a null pointer. -The reference returned is invalid after any other operations on the +The reference returned is invalid after any other operation on the object. However, the value of the storage referred to is retained, so that until the next call to @@ -1633,7 +1636,7 @@ // \ref{fpos.members}, members stateT state() const; void state(stateT); - private; + private: stateT st; // \expos }; } @@ -1678,7 +1681,7 @@ \oldconcept{Destructible} (\tref{cpp17.destructible}) requirements. If \tcode{is_trivially_copy_constructible_v} is \tcode{true}, then \tcode{fpos} has a trivial copy constructor. -If \tcode{is_trivially_copy_assignable} is \tcode{true}, +If \tcode{is_trivially_copy_assignable_v} is \tcode{true}, then \tcode{fpos} has a trivial copy assignment operator. If \tcode{is_trivially_destructible_v} is \tcode{true}, then \tcode{fpos} has a trivial destructor. @@ -3105,7 +3108,7 @@ \item the \tcode{getloc()} -member to a copy the global locale, +member to a copy of the global locale, \tcode{locale()}, at the time of construction. \end{itemize} @@ -3884,7 +3887,7 @@ \tcode{traits::eof()}. Otherwise, returns the value of \tcode{traits::to_int_type(*gptr())} -and increment the value of the next pointer for the input sequence. +and increments the value of the next pointer for the input sequence. \pnum \returns @@ -4162,6 +4165,15 @@ template Ostream&& operator<<(Ostream&& os, const T& x); + + // \ref{ostream.formatted.print}, print functions + template + void print(ostream& os, format_string fmt, Args&&... args); + template + void println(ostream& os, format_string fmt, Args&&... args); + + void vprint_unicode(ostream& os, string_view fmt, format_args args); + void vprint_nonunicode(ostream& os, string_view fmt, format_args args); } \end{codeblock} @@ -4203,6 +4215,30 @@ } \end{codeblock} +\rSec2[print.syn]{Header \tcode{} synopsis} + +\indexheader{print}% +\begin{codeblock} +namespace std { + // \ref{print.fun}, print functions + template + void print(format_string fmt, Args&&... args); + template + void print(FILE* stream, format_string fmt, Args&&... args); + + template + void println(format_string fmt, Args&&... args); + template + void println(FILE* stream, format_string fmt, Args&&... args); + + void vprint_unicode(string_view fmt, format_args args); + void vprint_unicode(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); +} +\end{codeblock} + \rSec2[input.streams]{Input streams} \rSec3[input.streams.general]{General} @@ -4216,6 +4252,13 @@ \rSec4[istream.general]{General} +\pnum +When a function is specified +with a type placeholder of \tcode{\placeholder{extended-floating-point-type}}, +the implementation provides overloads +for all cv-unqualified extended floating-point types\iref{basic.fundamental} +in lieu of \tcode{\placeholder{extended-floating-\brk{}point-type}}. + \indexlibraryglobal{basic_istream}% \begin{codeblock} namespace std { @@ -4253,6 +4296,7 @@ basic_istream& operator>>(float& f); basic_istream& operator>>(double& f); basic_istream& operator>>(long double& f); + basic_istream& operator>>(@\placeholder{extended-floating-point-type}@& f); basic_istream& operator>>(void*& p); basic_istream& operator>>(basic_streambuf* sb); @@ -4729,6 +4773,64 @@ \end{codeblock} \end{itemdescr} +\begin{itemdecl} +basic_istream& operator>>(@\placeholder{extended-floating-point-type}@& val); +\end{itemdecl} + +\begin{itemdescr} +\pnum +If +the floating-point conversion rank of \tcode{\placeholder{extended-floating-point-type}} +is not less than or equal to that of \tcode{long double}, +then an invocation of the operator function is conditionally supported +with \impldef{\tcode{operator>>} for large extended floating-point types} +semantics. + +\pnum +Otherwise, let \tcode{FP} be a standard floating-point type: +\begin{itemize} +\item +if the floating-point conversion rank of \tcode{\placeholder{extended-floating-point-type}} +is less than or equal to that of \tcode{float}, +then \tcode{FP} is \tcode{float}, +\item +otherwise, +if the floating-point conversion rank of \tcode{\placeholder{extended-floating-point-type}} +is less than or equal to that of \tcode{double}, +then \tcode{FP} is \tcode{double}, +\item +otherwise, \tcode{FP} is \tcode{long double}. +\end{itemize} + +\pnum +The conversion occurs as if performed by the following code fragment +(using the same notation as for the preceding code fragment): +\begin{codeblock} +using numget = num_get>; +iostate err = ios_base::goodbit; +FP fval; +use_facet(loc).get(*this, 0, *this, err, fval); +if (fval < -numeric_limits<@\placeholder{extended-floating-point-type}@>::max()) { + err |= ios_base::failbit; + val = -numeric_limits<@\placeholder{extended-floating-point-type}@>::max(); +} else if (numeric_limits<@\placeholder{extended-floating-point-type}@>::max() < fval) { + err |= ios_base::failbit; + val = numeric_limits<@\placeholder{extended-floating-point-type}@>::max(); +} else { + val = static_cast<@\placeholder{extended-floating-point-type}@>(fval); +} +setstate(err); +\end{codeblock} +\begin{note} +When the extended floating-point type has +a floating-point conversion rank +that is not equal to the rank of any standard floating-point type, +then double rounding during the conversion can result in inaccurate results. +\tcode{from_chars} can be used in situations +where maximum accuracy is important. +\end{note} +\end{itemdescr} + \rSec4[istream.extractors]{\tcode{basic_istream::operator>>}} \indexlibrarymember{operator>>}{basic_istream}% @@ -5811,6 +5913,12 @@ \rSec4[ostream.general]{General} +\pnum +When a function has +a parameter type \tcode{\placeholder{extended-floating-point-type}}, +the implementation provides overloads +for all cv-unqualified extended floating-point types\iref{basic.fundamental}. + \indexlibraryglobal{basic_ostream}% \begin{codeblock} namespace std { @@ -5848,6 +5956,7 @@ basic_ostream& operator<<(float f); basic_ostream& operator<<(double f); basic_ostream& operator<<(long double f); + basic_ostream& operator<<(@\placeholder{extended-floating-point-type}@ f); basic_ostream& operator<<(const void* p); basic_ostream& operator<<(const volatile void* p); @@ -6427,6 +6536,44 @@ Equivalent to: \tcode{return operator<<(const_cast(p));} \end{itemdescr} +\begin{itemdecl} +basic_ostream& operator<<(@\placeholder{extended-floating-point-type}@ val); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If the floating-point conversion rank of \tcode{\placeholder{extended-floating-point-type}} +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(); +\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(); +\end{codeblock} +Otherwise, an invocation of the operator function is conditionally supported +with \impldef{\tcode{operator<<} for large extended floating-point types} +semantics. + +If \tcode{failed} is \tcode{true} then does \tcode{setstate(badbit)}, +which may throw an exception, and returns. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + \rSec4[ostream.inserters]{\tcode{basic_ostream::operator<<}} \indexlibrarymember{operator<<}{basic_ostream}% @@ -6656,6 +6803,92 @@ \tcode{out}. \end{itemdescr} +\rSec4[ostream.formatted.print]{Print} + +\indexlibraryglobal{print}% +\begin{itemdecl} +template + void print(ostream& os, format_string fmt, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\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)...)); +\end{codeblock} +Otherwise, equivalent to: +\begin{codeblock} +vprint_nonunicode(os, fmt.@\exposid{str}@, make_format_args(std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{println}% +\begin{itemdecl} +template + void println(ostream& os, format_string fmt, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +print(os, "{}\n", format(fmt, std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{vprint_unicode}% +\indexlibraryglobal{vprint_nonunicode}% +\begin{itemdecl} +void vprint_unicode(ostream& os, string_view fmt, format_args args); +void vprint_nonunicode(ostream& os, string_view fmt, format_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Behaves as a formatted output function\iref{ostream.formatted.reqmts} +of \tcode{os}, except that: +\begin{itemize} +\item +failure to generate output is reported as specified below, and +\item +any exception thrown by the call to \tcode{vformat} is propagated +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} +After constructing a \tcode{sentry} object, +the function initializes an automatic variable via +\begin{codeblock} +string out = vformat(os.getloc(), fmt, args); +\end{codeblock} +If the function is \tcode{vprint_unicode} and +\tcode{os} is a stream that refers to a terminal capable of displaying Unicode +which is determined in an implementation-defined manner, +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. +Otherwise (if \tcode{os} is not such a stream or +the function is \tcode{vprint_nonunicode}), +inserts the character sequence +\range{out.begin()}{out.end()} into \tcode{os}. +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}). + +\pnum +\recommended +For \tcode{vprint_unicode}, +if invoking the native Unicode API requires transcoding, +implementations should substitute invalid code units +with \unicode{fffd}{replacement character} per +The Unicode Standard Version 14.0 - Core Specification, Chapter 3.9. +\end{itemdescr} + \rSec3[ostream.unformatted]{Unformatted output functions} \pnum @@ -7462,6 +7695,169 @@ \end{itemize} \end{itemdescr} +\rSec2[print.fun]{Print functions} + +\indexlibraryglobal{print}% +\begin{itemdecl} +template + void print(format_string fmt, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +print(stdout, fmt, std::forward(args)...); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{print}% +\begin{itemdecl} +template + void print(FILE* stream, format_string fmt, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +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)...)); +\end{codeblock} +Otherwise, equivalent to: +\begin{codeblock} +vprint_nonunicode(stream, fmt.@\exposid{str}@, make_format_args(std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{println}% +\begin{itemdecl} +template + void println(format_string fmt, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +println(stdout, fmt, std::forward(args)...); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{println}% +\begin{itemdecl} +template + void println(FILE* stream, format_string fmt, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +print(stream, "{}\n", format(fmt, std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{vprint_unicode}% +\begin{itemdecl} +void vprint_unicode(string_view fmt, format_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +vprint_unicode(stdout, fmt, args); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{vprint_unicode}% +\begin{itemdecl} +void vprint_unicode(FILE* stream, string_view fmt, format_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{stream} is a valid pointer to an output C stream. + +\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, +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. +Otherwise writes \tcode{out} to \tcode{stream} unchanged. +\begin{note} +On POSIX and Windows, \tcode{stream} referring to a terminal means that, +respectively, +\tcode{isatty(fileno(\linebreak{}stream))} and +\tcode{GetConsoleMode(_get_osfhandle(_fileno(stream)), ...)} +return nonzero. +\end{note} +\begin{note} +On Windows, the native Unicode API is \tcode{WriteConsoleW}. +\end{note} + +\pnum +\throws +Any exception thrown by the call to \tcode{vformat}\iref{format.err.report}. +\tcode{system_error} if writing to the terminal or \tcode{stream} fails. +May throw \tcode{bad_alloc}. + +\pnum +\recommended +If invoking the native Unicode API requires transcoding, +implementations should substitute invalid code units +with \unicode{fffd}{replacement character} per +The Unicode Standard Version 14.0 - Core Specification, Chapter 3.9. +\end{itemdescr} + +\indexlibraryglobal{vprint_nonunicode}% +\begin{itemdecl} +void vprint_nonunicode(string_view fmt, format_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +vprint_nonunicode(stdout, fmt, args); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{vprint_nonunicode}% +\begin{itemdecl} +void vprint_nonunicode(FILE* stream, string_view fmt, format_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{stream} is a valid pointer to an output C stream. + +\pnum +\effects +Writes the result of \tcode{vformat(fmt, args)} to \tcode{stream}. + +\pnum +\throws +Any exception thrown by the call to \tcode{vformat}\iref{format.err.report}. +\tcode{system_error} if writing to \tcode{stream} fails. +May throw \tcode{bad_alloc}. +\end{itemdescr} + \rSec1[string.streams]{String-based streams} \rSec2[sstream.syn]{Header \tcode{} synopsis} @@ -8320,7 +8716,7 @@ \indexlibrarymember{setbuf}{basic_streambuf}% \begin{itemdecl} -basic_streambuf* setbuf(charT* s, streamsize n); +basic_streambuf* setbuf(charT* s, streamsize n) override; \end{itemdecl} \begin{itemdescr} @@ -9330,30 +9726,42 @@ template> class basic_spanbuf; + template + void swap(basic_spanbuf& x, basic_spanbuf& y); + using spanbuf = basic_spanbuf; using wspanbuf = basic_spanbuf; template> class basic_ispanstream; + template + void swap(basic_ispanstream& x, basic_ispanstream& y); + using ispanstream = basic_ispanstream; using wispanstream = basic_ispanstream; template> class basic_ospanstream; + template + void swap(basic_ospanstream& x, basic_ospanstream& y); + using ospanstream = basic_ospanstream; using wospanstream = basic_ospanstream; template> class basic_spanstream; + template + void swap(basic_spanstream& x, basic_spanstream& y); + using spanstream = basic_spanstream; using wspanstream = basic_spanstream; } \end{codeblock} -\rSec2[spanbuf]{Class template \tcode{spanbuf}} +\rSec2[spanbuf]{Class template \tcode{basic_spanbuf}} \rSec3[spanbuf.general]{General} @@ -9370,7 +9778,7 @@ using off_type = typename traits::off_type; using traits_type = traits; - // \ref{spanbuf.ctor}, constructors + // \ref{spanbuf.cons}, constructors basic_spanbuf() : basic_spanbuf(ios_base::in | ios_base::out) {} explicit basic_spanbuf(ios_base::openmode which) : basic_spanbuf(std::span(), which) {} @@ -9399,9 +9807,6 @@ ios_base::openmode @\exposid{mode}@; // \expos std::span @\exposid{buf}@; // \expos }; - -template - void swap(basic_spanbuf& x, basic_spanbuf& y); } \end{codeblock} @@ -9423,7 +9828,7 @@ the underlying character sequence. \end{itemize} -\rSec3[spanbuf.ctor]{Constructors} +\rSec3[spanbuf.cons]{Constructors} \indexlibraryctor{basic_spanbuf}% \begin{itemdecl} @@ -9699,7 +10104,7 @@ using off_type = typename traits::off_type; using traits_type = traits; - // \ref{ispanstream.ctor}, constructors + // \ref{ispanstream.cons}, constructors explicit basic_ispanstream(std::span s, ios_base::openmode which = ios_base::in); basic_ispanstream(const basic_ispanstream&) = delete; @@ -9722,9 +10127,6 @@ private: basic_spanbuf sb; // \expos }; - - template - void swap(basic_ispanstream& x, basic_ispanstream& y); } \end{codeblock} @@ -9735,7 +10137,7 @@ in the underlying \tcode{spanbuf}. \end{note} -\rSec3[ispanstream.ctor]{Constructors} +\rSec3[ispanstream.cons]{Constructors} \indexlibraryctor{basic_ispanstream}% \begin{itemdecl} @@ -9748,7 +10150,7 @@ Initializes the base class with \tcode{basic_istream(addressof(sb))} and \tcode{sb} with -\tcode{basic_spanbuf(s, which | ios_base::in)}\iref{spanbuf.ctor}. +\tcode{basic_spanbuf(s, which | ios_base::in)}\iref{spanbuf.cons}. \end{itemdescr} \indexlibraryctor{basic_ispanstream}% @@ -9890,7 +10292,7 @@ using off_type = typename traits::off_type; using traits_type = traits; - // \ref{ospanstream.ctor}, constructors + // \ref{ospanstream.cons}, constructors explicit basic_ospanstream(std::span s, ios_base::openmode which = ios_base::out); basic_ospanstream(const basic_ospanstream&) = delete; @@ -9910,13 +10312,10 @@ private: basic_spanbuf sb; // \expos }; - - template - void swap(basic_ospanstream& x, basic_ospanstream& y); } \end{codeblock} -\rSec3[ospanstream.ctor]{Constructors} +\rSec3[ospanstream.cons]{Constructors} \indexlibraryctor{basic_ospanstream}% \begin{itemdecl} @@ -9930,7 +10329,7 @@ Initializes the base class with \tcode{basic_ostream(addressof(sb))} and \tcode{sb} with -\tcode{basic_spanbuf(s, which | ios_base::out)}\iref{spanbuf.ctor}. +\tcode{basic_spanbuf(s, which | ios_base::out)}\iref{spanbuf.cons}. \end{itemdescr} \indexlibraryctor{basic_ospanstream}% @@ -10031,7 +10430,7 @@ using off_type = typename traits::off_type; using traits_type = traits; - // \ref{spanstream.ctor}, constructors + // \ref{spanstream.cons}, constructors explicit basic_spanstream(std::span s, ios_base::openmode which = ios_base::out | ios_base::in); basic_spanstream(const basic_spanstream&) = delete; @@ -10051,13 +10450,10 @@ private: basic_spanbuf sb; // \expos }; - - template - void swap(basic_spanstream& x, basic_spanstream& y); } \end{codeblock} -\rSec3[spanstream.ctor]{Constructors} +\rSec3[spanstream.cons]{Constructors} \indexlibraryctor{basic_spanstream}% \begin{itemdecl} @@ -10071,7 +10467,7 @@ Initializes the base class with \tcode{basic_iostream(addressof(sb))} and \tcode{sb} with -\tcode{basic_spanbuf(s, which)}\iref{spanbuf.ctor}. +\tcode{basic_spanbuf(s, which)}\iref{spanbuf.cons}. \end{itemdescr} \indexlibraryctor{basic_spanstream}% @@ -10507,28 +10903,34 @@ the open fails. \begin{floattable}{File open modes}{filebuf.open.modes} -{cccccl} +{ccccccl} \topline -\multicolumn{5}{|c}{\tcode{ios_base} flag combination} & \tcode{stdio} equivalent \\ -\tcode{binary} & \tcode{in} & \tcode{out} & \tcode{trunc} & \tcode{app} & \\ \capsep - & & + & & & \tcode{"w"} \\ \rowsep - & & + & + & & \tcode{"w"} \\ \rowsep - & & + & & + & \tcode{"a"} \\ \rowsep - & & & & + & \tcode{"a"} \\ \rowsep - & + & & & & \tcode{"r"} \\ \rowsep - & + & + & & & \tcode{"r+"} \\ \rowsep - & + & + & + & & \tcode{"w+"} \\ \rowsep - & + & + & & + & \tcode{"a+"} \\ \rowsep - & + & & & + & \tcode{"a+"} \\ \rowsep - + & & + & & & \tcode{"wb"} \\ \rowsep - + & & + & + & & \tcode{"wb"} \\ \rowsep - + & & + & & + & \tcode{"ab"} \\ \rowsep - + & & & & + & \tcode{"ab"} \\ \rowsep - + & + & & & & \tcode{"rb"} \\ \rowsep - + & + & + & & & \tcode{"r+b"} \\ \rowsep - + & + & + & + & & \tcode{"w+b"} \\ \rowsep - + & + & + & & + & \tcode{"a+b"} \\ \rowsep - + & + & & & + & \tcode{"a+b"} \\ +\multicolumn{6}{|c}{\tcode{ios_base} flag combination} & \tcode{stdio} equivalent \\ +\tcode{binary} & \tcode{in} & \tcode{out} & \tcode{trunc} & \tcode{app} & \tcode{noreplace} \\ \capsep + & & + & & & & \tcode{"w"} \\ \rowsep + & & + & & & + & \tcode{"wx"} \\ \rowsep + & & + & + & & & \tcode{"w"} \\ \rowsep + & & + & + & & + & \tcode{"wx"} \\ \rowsep + & & + & & + & & \tcode{"a"} \\ \rowsep + & & & & + & & \tcode{"a"} \\ \rowsep + & + & & & & & \tcode{"r"} \\ \rowsep + & + & + & & & & \tcode{"r+"} \\ \rowsep + & + & + & + & & & \tcode{"w+"} \\ \rowsep + & + & + & + & & + & \tcode{"w+x"} \\ \rowsep + & + & + & & + & & \tcode{"a+"} \\ \rowsep + & + & & & + & & \tcode{"a+"} \\ \rowsep + + & & + & & & & \tcode{"wb"} \\ \rowsep + + & & + & & & + & \tcode{"wbx"} \\ \rowsep + + & & + & + & & & \tcode{"wb"} \\ \rowsep + + & & + & + & & + & \tcode{"wbx"} \\ \rowsep + + & & + & & + & & \tcode{"ab"} \\ \rowsep + + & & & & + & & \tcode{"ab"} \\ \rowsep + + & + & & & & & \tcode{"rb"} \\ \rowsep + + & + & + & & & & \tcode{"r+b"} \\ \rowsep + + & + & + & + & & & \tcode{"w+b"} \\ \rowsep + + & + & + & + & & + & \tcode{"w+bx"} \\ \rowsep + + & + & + & & + & & \tcode{"a+b"} \\ \rowsep + + & + & & & + & & \tcode{"a+b"} \\ \end{floattable} \pnum @@ -12217,7 +12619,7 @@ \pnum \ensures The value returned by \tcode{get_wrapped()} -is the value returned by \tcode{os.get_wrapped()} +is the value returned by \tcode{other.get_wrapped()} prior to calling this constructor. \tcode{nullptr == other.get_wrapped()} is \tcode{true}. \end{itemdescr} @@ -13077,7 +13479,7 @@ network or other resource locations. Some operating systems define a single letter followed by a colon -as a drive specifier -- a \grammarterm{root-name} +as a drive specifier --- a \grammarterm{root-name} identifying a specific device such as a disk drive. \end{note} @@ -14963,10 +15365,10 @@ \tcode{permissions} shall replace the file's permission bits with \tcode{perm} \\ \rowsep \tcode{add} & \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 + the bitwise \logop{or} of \tcode{perm} and the file's current permission bits. \\ \rowsep \tcode{remove} & \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 + the bitwise \logop{and} of the complement of \tcode{perm} and the file's current permission bits. \\ \rowsep \tcode{nofollow} & \tcode{permissions} shall change the permissions of a symbolic link itself rather than the permissions of the file the link resolves to. \\ @@ -15646,6 +16048,10 @@ directory_iterator& operator++(); directory_iterator& increment(error_code& ec); + bool operator==(default_sentinel_t) const noexcept { + return *this == directory_iterator(); + } + // other members as required by \ref{input.iterators}, input iterators }; } @@ -15892,6 +16298,10 @@ void pop(error_code& ec); void disable_recursion_pending(); + bool operator==(default_sentinel_t) const noexcept { + return *this == recursive_directory_iterator(); + } + // other members as required by \ref{input.iterators}, input iterators }; } diff --git a/source/iterators.tex b/source/iterators.tex index 14e44f0150..cf6b9b8374 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -45,30 +45,30 @@ // \ref{iterator.assoc.types}, associated types // \ref{incrementable.traits}, incrementable traits - template struct incrementable_traits; + template struct incrementable_traits; // freestanding template - using iter_difference_t = @\seebelow@; + using iter_difference_t = @\seebelow@; // freestanding // \ref{readable.traits}, indirectly readable traits - template struct indirectly_readable_traits; + template struct indirectly_readable_traits; // freestanding template - using iter_value_t = @\seebelow@; + using iter_value_t = @\seebelow@; // freestanding // \ref{iterator.traits}, iterator traits - template struct iterator_traits; - template requires is_object_v struct iterator_traits; + template struct iterator_traits; // freestanding + template requires is_object_v struct iterator_traits; // freestanding template<@\exposconcept{dereferenceable}@ T> - using iter_reference_t = decltype(*declval()); + using iter_reference_t = decltype(*declval()); // freestanding namespace ranges { // \ref{iterator.cust}, customization point objects inline namespace @\unspec@ { // \ref{iterator.cust.move}, \tcode{ranges::iter_move} - inline constexpr @\unspec@ iter_move = @\unspec@; + inline constexpr @\unspec@ iter_move = @\unspec@; // freestanding // \ref{iterator.cust.swap}, \tcode{ranges::iter_swap} - inline constexpr @\unspec@ iter_swap = @\unspec@; + inline constexpr @\unspec@ iter_swap = @\unspec@; // freestanding } } @@ -76,324 +76,359 @@ requires requires(T& t) { { ranges::iter_move(t) } -> @\exposconcept{can-reference}@; } - using iter_rvalue_reference_t + using iter_rvalue_reference_t // freestanding = decltype(ranges::iter_move(declval())); // \ref{iterator.concepts}, iterator concepts // \ref{iterator.concept.readable}, concept \libconcept{indirectly_readable} template - concept indirectly_readable = @\seebelow@; + concept indirectly_readable = @\seebelow@; // freestanding template<@\libconcept{indirectly_readable}@ T> - using iter_common_reference_t = + using iter_common_reference_t = // freestanding common_reference_t, iter_value_t&>; // \ref{iterator.concept.writable}, concept \libconcept{indirectly_writable} template - concept indirectly_writable = @\seebelow@; + concept indirectly_writable = @\seebelow@; // freestanding // \ref{iterator.concept.winc}, concept \libconcept{weakly_incrementable} template - concept weakly_incrementable = @\seebelow@; + concept weakly_incrementable = @\seebelow@; // freestanding // \ref{iterator.concept.inc}, concept \libconcept{incrementable} template - concept incrementable = @\seebelow@; + concept incrementable = @\seebelow@; // freestanding // \ref{iterator.concept.iterator}, concept \libconcept{input_or_output_iterator} template - concept input_or_output_iterator = @\seebelow@; + concept input_or_output_iterator = @\seebelow@; // freestanding // \ref{iterator.concept.sentinel}, concept \libconcept{sentinel_for} template - concept sentinel_for = @\seebelow@; + concept sentinel_for = @\seebelow@; // freestanding // \ref{iterator.concept.sizedsentinel}, concept \libconcept{sized_sentinel_for} template - inline constexpr bool disable_sized_sentinel_for = false; + inline constexpr bool disable_sized_sentinel_for = false; // freestanding template - concept sized_sentinel_for = @\seebelow@; + concept sized_sentinel_for = @\seebelow@; // freestanding // \ref{iterator.concept.input}, concept \libconcept{input_iterator} template - concept input_iterator = @\seebelow@; + concept input_iterator = @\seebelow@; // freestanding // \ref{iterator.concept.output}, concept \libconcept{output_iterator} template - concept output_iterator = @\seebelow@; + concept output_iterator = @\seebelow@; // freestanding // \ref{iterator.concept.forward}, concept \libconcept{forward_iterator} template - concept forward_iterator = @\seebelow@; + concept forward_iterator = @\seebelow@; // freestanding // \ref{iterator.concept.bidir}, concept \libconcept{bidirectional_iterator} template - concept bidirectional_iterator = @\seebelow@; + concept bidirectional_iterator = @\seebelow@; // freestanding // \ref{iterator.concept.random.access}, concept \libconcept{random_access_iterator} template - concept random_access_iterator = @\seebelow@; + concept random_access_iterator = @\seebelow@; // freestanding // \ref{iterator.concept.contiguous}, concept \libconcept{contiguous_iterator} template - concept contiguous_iterator = @\seebelow@; + concept contiguous_iterator = @\seebelow@; // freestanding // \ref{indirectcallable}, indirect callable requirements // \ref{indirectcallable.indirectinvocable}, indirect callables template - concept indirectly_unary_invocable = @\seebelow@; + concept indirectly_unary_invocable = @\seebelow@; // freestanding template - concept indirectly_regular_unary_invocable = @\seebelow@; + concept indirectly_regular_unary_invocable = @\seebelow@; // freestanding template - concept indirect_unary_predicate = @\seebelow@; + concept indirect_unary_predicate = @\seebelow@; // freestanding template - concept indirect_binary_predicate = @\seebelow@; + concept indirect_binary_predicate = @\seebelow@; // freestanding template - concept indirect_equivalence_relation = @\seebelow@; + concept indirect_equivalence_relation = @\seebelow@; // freestanding template - concept indirect_strict_weak_order = @\seebelow@; + concept indirect_strict_weak_order = @\seebelow@; // freestanding template requires (@\libconcept{indirectly_readable}@ && ...) && @\libconcept{invocable}@...> - using indirect_result_t = invoke_result_t...>; + using indirect_result_t = invoke_result_t...>; // freestanding // \ref{projected}, projected template<@\libconcept{indirectly_readable}@ I, @\libconcept{indirectly_regular_unary_invocable}@ Proj> - struct projected; + struct projected; // freestanding template<@\libconcept{weakly_incrementable}@ I, class Proj> - struct incrementable_traits>; + struct incrementable_traits>; // freestanding // \ref{alg.req}, common algorithm requirements // \ref{alg.req.ind.move}, concept \libconcept{indirectly_movable} template - concept indirectly_movable = @\seebelow@; + concept indirectly_movable = @\seebelow@; // freestanding template - concept indirectly_movable_storable = @\seebelow@; + concept indirectly_movable_storable = @\seebelow@; // freestanding // \ref{alg.req.ind.copy}, concept \libconcept{indirectly_copyable} template - concept indirectly_copyable = @\seebelow@; + concept indirectly_copyable = @\seebelow@; // freestanding template - concept indirectly_copyable_storable = @\seebelow@; + concept indirectly_copyable_storable = @\seebelow@; // freestanding // \ref{alg.req.ind.swap}, concept \libconcept{indirectly_swappable} template - concept indirectly_swappable = @\seebelow@; + concept indirectly_swappable = @\seebelow@; // freestanding // \ref{alg.req.ind.cmp}, concept \libconcept{indirectly_comparable} template - concept indirectly_comparable = @\seebelow@; + concept indirectly_comparable = @\seebelow@; // freestanding // \ref{alg.req.permutable}, concept \libconcept{permutable} template - concept permutable = @\seebelow@; + concept permutable = @\seebelow@; // freestanding // \ref{alg.req.mergeable}, concept \libconcept{mergeable} template - concept mergeable = @\seebelow@; + concept mergeable = @\seebelow@; // freestanding // \ref{alg.req.sortable}, concept \libconcept{sortable} template - concept sortable = @\seebelow@; + concept sortable = @\seebelow@; // freestanding // \ref{iterator.primitives}, primitives // \ref{std.iterator.tags}, iterator tags - struct input_iterator_tag { }; - struct output_iterator_tag { }; - struct forward_iterator_tag: public input_iterator_tag { }; - struct bidirectional_iterator_tag: public forward_iterator_tag { }; - struct random_access_iterator_tag: public bidirectional_iterator_tag { }; - struct contiguous_iterator_tag: public random_access_iterator_tag { }; + struct input_iterator_tag { }; // freestanding + struct output_iterator_tag { }; // freestanding + struct forward_iterator_tag: public input_iterator_tag { }; // freestanding + struct bidirectional_iterator_tag: public forward_iterator_tag { }; // freestanding + struct random_access_iterator_tag: public bidirectional_iterator_tag { }; // freestanding + struct contiguous_iterator_tag: public random_access_iterator_tag { }; // freestanding // \ref{iterator.operations}, iterator operations template constexpr void - advance(InputIterator& i, Distance n); + advance(InputIterator& i, Distance n); // freestanding template constexpr typename iterator_traits::difference_type - distance(InputIterator first, InputIterator last); + distance(InputIterator first, InputIterator last); // freestanding template constexpr InputIterator - next(InputIterator x, + next(InputIterator x, // freestanding typename iterator_traits::difference_type n = 1); template constexpr BidirectionalIterator - prev(BidirectionalIterator x, + prev(BidirectionalIterator x, // freestanding typename iterator_traits::difference_type n = 1); // \ref{range.iter.ops}, range iterator operations namespace ranges { // \ref{range.iter.op.advance}, \tcode{ranges::advance} template<@\libconcept{input_or_output_iterator}@ I> - constexpr void advance(I& i, iter_difference_t n); + constexpr void advance(I& i, iter_difference_t n); // freestanding template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sentinel_for}@ S> - constexpr void advance(I& i, S bound); + constexpr void advance(I& i, S bound); // freestanding template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sentinel_for}@ S> - constexpr iter_difference_t advance(I& i, iter_difference_t n, S bound); + constexpr iter_difference_t advance(I& i, iter_difference_t n, // freestanding + S bound); // \ref{range.iter.op.distance}, \tcode{ranges::distance} template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sentinel_for}@ S> requires (!@\libconcept{sized_sentinel_for}@) - constexpr iter_difference_t distance(I first, S last); + constexpr iter_difference_t distance(I first, S last); // freestanding template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sized_sentinel_for}@ S> - constexpr iter_difference_t distance(const I& first, const S& last); + constexpr iter_difference_t distance(const I& first, const S& last); // freestanding template<@\libconcept{range}@ R> - constexpr range_difference_t distance(R&& r); + constexpr range_difference_t distance(R&& r); // freestanding // \ref{range.iter.op.next}, \tcode{ranges::next} template<@\libconcept{input_or_output_iterator}@ I> - constexpr I next(I x); + constexpr I next(I x); // freestanding template<@\libconcept{input_or_output_iterator}@ I> - constexpr I next(I x, iter_difference_t n); + constexpr I next(I x, iter_difference_t n); // freestanding template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sentinel_for}@ S> - constexpr I next(I x, S bound); + constexpr I next(I x, S bound); // freestanding template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sentinel_for}@ S> - constexpr I next(I x, iter_difference_t n, S bound); + constexpr I next(I x, iter_difference_t n, S bound); // freestanding // \ref{range.iter.op.prev}, \tcode{ranges::prev} template<@\libconcept{bidirectional_iterator}@ I> - constexpr I prev(I x); + constexpr I prev(I x); // freestanding template<@\libconcept{bidirectional_iterator}@ I> - constexpr I prev(I x, iter_difference_t n); + constexpr I prev(I x, iter_difference_t n); // freestanding template<@\libconcept{bidirectional_iterator}@ I> - constexpr I prev(I x, iter_difference_t n, I bound); + constexpr I prev(I x, iter_difference_t n, I bound); // freestanding } // \ref{predef.iterators}, predefined iterators and sentinels // \ref{reverse.iterators}, reverse iterators - template class reverse_iterator; + template class reverse_iterator; // freestanding template - constexpr bool operator==( + constexpr bool operator==( // freestanding const reverse_iterator& x, const reverse_iterator& y); template - constexpr bool operator!=( + constexpr bool operator!=( // freestanding const reverse_iterator& x, const reverse_iterator& y); template - constexpr bool operator<( + constexpr bool operator<( // freestanding const reverse_iterator& x, const reverse_iterator& y); template - constexpr bool operator>( + constexpr bool operator>( // freestanding const reverse_iterator& x, const reverse_iterator& y); template - constexpr bool operator<=( + constexpr bool operator<=( // freestanding const reverse_iterator& x, const reverse_iterator& y); template - constexpr bool operator>=( + constexpr bool operator>=( // freestanding const reverse_iterator& x, const reverse_iterator& y); template Iterator2> constexpr compare_three_way_result_t - operator<=>(const reverse_iterator& x, + operator<=>(const reverse_iterator& x, // freestanding const reverse_iterator& y); template - constexpr auto operator-( + constexpr auto operator-( // freestanding const reverse_iterator& x, const reverse_iterator& y) -> decltype(y.base() - x.base()); template - constexpr reverse_iterator operator+( + constexpr reverse_iterator operator+( // freestanding iter_difference_t n, const reverse_iterator& x); template - constexpr reverse_iterator make_reverse_iterator(Iterator i); + constexpr reverse_iterator make_reverse_iterator(Iterator i); // freestanding template requires (!@\libconcept{sized_sentinel_for}@) - inline constexpr bool disable_sized_sentinel_for, + inline constexpr bool disable_sized_sentinel_for, // freestanding reverse_iterator> = true; // \ref{insert.iterators}, insert iterators - template class back_insert_iterator; + template class back_insert_iterator; // freestanding template - constexpr back_insert_iterator back_inserter(Container& x); + constexpr back_insert_iterator back_inserter(Container& x); // freestanding - template class front_insert_iterator; + template class front_insert_iterator; // freestanding template - constexpr front_insert_iterator front_inserter(Container& x); + constexpr front_insert_iterator front_inserter(Container& x); // freestanding - template class insert_iterator; + template class insert_iterator; // freestanding template constexpr insert_iterator - inserter(Container& x, ranges::iterator_t i); + inserter(Container& x, ranges::iterator_t i); // freestanding + + // \ref{const.iterators}, constant iterators and sentinels + // \ref{const.iterators.alias}, alias templates + template<@\libconcept{indirectly_readable}@ I> + using iter_const_reference_t = @\seebelow@; // freestanding + template + concept @\exposconcept{constant-iterator}@ = @\seebelow@; // \expos + template<@\libconcept{input_iterator}@ I> + using const_iterator = @\seebelow@; // freestanding + template + using const_sentinel = @\seebelow@; // freestanding + + // \ref{const.iterators.iterator}, class template \tcode{basic_const_iterator} + template + class basic_const_iterator; // freestanding + + template U> + struct common_type, U> { // freestanding + using type = basic_const_iterator>; + }; + template U> + struct common_type> { // freestanding + using type = basic_const_iterator>; + }; + template U> + struct common_type, basic_const_iterator> { // freestanding + using type = basic_const_iterator>; + }; + + template<@\libconcept{input_iterator}@ I> + constexpr const_iterator make_const_iterator(I it) { return it; } // freestanding + + template + constexpr const_sentinel make_const_sentinel(S s) { return s; } // freestanding // \ref{move.iterators}, move iterators and sentinels - template class move_iterator; + template class move_iterator; // freestanding template - constexpr bool operator==( + constexpr bool operator==( // freestanding const move_iterator& x, const move_iterator& y); template - constexpr bool operator<( + constexpr bool operator<( // freestanding const move_iterator& x, const move_iterator& y); template - constexpr bool operator>( + constexpr bool operator>( // freestanding const move_iterator& x, const move_iterator& y); template - constexpr bool operator<=( + constexpr bool operator<=( // freestanding const move_iterator& x, const move_iterator& y); template - constexpr bool operator>=( + constexpr bool operator>=( // freestanding const move_iterator& x, const move_iterator& y); template Iterator2> constexpr compare_three_way_result_t - operator<=>(const move_iterator& x, + operator<=>(const move_iterator& x, // freestanding const move_iterator& y); template - constexpr auto operator-( + constexpr auto operator-( // freestanding const move_iterator& x, const move_iterator& y) -> decltype(x.base() - y.base()); template constexpr move_iterator - operator+(iter_difference_t n, const move_iterator& x); + operator+(iter_difference_t n, const move_iterator& x); // freestanding template - constexpr move_iterator make_move_iterator(Iterator i); + constexpr move_iterator make_move_iterator(Iterator i); // freestanding - template<@\libconcept{semiregular}@ S> class move_sentinel; + template<@\libconcept{semiregular}@ S> class move_sentinel; // freestanding // \ref{iterators.common}, common iterators template<@\libconcept{input_or_output_iterator}@ I, @\libconcept{sentinel_for}@ S> requires (!@\libconcept{same_as}@ && @\libconcept{copyable}@) - class common_iterator; + class common_iterator; // freestanding template - struct incrementable_traits>; + struct incrementable_traits>; // freestanding template<@\libconcept{input_iterator}@ I, class S> - struct iterator_traits>; + struct iterator_traits>; // freestanding // \ref{default.sentinel}, default sentinel - struct default_sentinel_t; - inline constexpr default_sentinel_t @\libglobal{default_sentinel}@{}; + struct default_sentinel_t; // freestanding + inline constexpr default_sentinel_t @\libglobal{default_sentinel}@{}; // freestanding // \ref{iterators.counted}, counted iterators - template<@\libconcept{input_or_output_iterator}@ I> class counted_iterator; + template<@\libconcept{input_or_output_iterator}@ I> class counted_iterator; // freestanding template<@\libconcept{input_iterator}@ I> requires @\seebelow@ - struct iterator_traits>; + struct iterator_traits>; // freestanding // \ref{unreachable.sentinel}, unreachable sentinel - struct unreachable_sentinel_t; - inline constexpr unreachable_sentinel_t @\libglobal{unreachable_sentinel}@{}; + struct unreachable_sentinel_t; // freestanding + inline constexpr unreachable_sentinel_t @\libglobal{unreachable_sentinel}@{}; // freestanding // \ref{stream.iterators}, stream iterators template, @@ -416,39 +451,53 @@ class ostreambuf_iterator; // \ref{iterator.range}, range access - template constexpr auto begin(C& c) -> decltype(c.begin()); - template constexpr auto begin(const C& c) -> decltype(c.begin()); - template constexpr auto end(C& c) -> decltype(c.end()); - template constexpr auto end(const C& c) -> decltype(c.end()); - template constexpr T* begin(T (&array)[N]) noexcept; - template constexpr T* end(T (&array)[N]) noexcept; - template constexpr auto cbegin(const C& c) noexcept(noexcept(std::begin(c))) - -> decltype(std::begin(c)); - template constexpr auto cend(const C& c) noexcept(noexcept(std::end(c))) - -> decltype(std::end(c)); - template constexpr auto rbegin(C& c) -> decltype(c.rbegin()); - template constexpr auto rbegin(const C& c) -> decltype(c.rbegin()); - template constexpr auto rend(C& c) -> decltype(c.rend()); - template constexpr auto rend(const C& c) -> decltype(c.rend()); - template constexpr reverse_iterator rbegin(T (&array)[N]); - template constexpr reverse_iterator rend(T (&array)[N]); - template constexpr reverse_iterator rbegin(initializer_list il); - template constexpr reverse_iterator rend(initializer_list il); - template constexpr auto crbegin(const C& c) -> decltype(std::rbegin(c)); - template constexpr auto crend(const C& c) -> decltype(std::rend(c)); - - template constexpr auto size(const C& c) -> decltype(c.size()); - template constexpr size_t size(const T (&array)[N]) noexcept; - template constexpr auto ssize(const C& c) - -> common_type_t>; - template constexpr ptrdiff_t ssize(const T (&array)[N]) noexcept; - template [[nodiscard]] constexpr auto empty(const C& c) -> decltype(c.empty()); - template [[nodiscard]] constexpr bool empty(const T (&array)[N]) noexcept; - template [[nodiscard]] constexpr bool empty(initializer_list il) noexcept; - template constexpr auto data(C& c) -> decltype(c.data()); - template constexpr auto data(const C& c) -> decltype(c.data()); - template constexpr T* data(T (&array)[N]) noexcept; - template constexpr const E* data(initializer_list il) noexcept; + template constexpr auto begin(C& c) -> decltype(c.begin()); // freestanding + template constexpr auto begin(const C& c) -> decltype(c.begin()); // freestanding + template constexpr auto end(C& c) -> decltype(c.end()); // freestanding + template constexpr auto end(const C& c) -> decltype(c.end()); // freestanding + template constexpr T* begin(T (&array)[N]) noexcept; // freestanding + template constexpr T* end(T (&array)[N]) noexcept; // freestanding + template constexpr auto cbegin(const C& c) // freestanding + noexcept(noexcept(std::begin(c))) -> decltype(std::begin(c)); + template constexpr auto cend(const C& c) // freestanding + noexcept(noexcept(std::end(c))) -> decltype(std::end(c)); + template constexpr auto rbegin(C& c) -> decltype(c.rbegin()); // freestanding + template constexpr auto rbegin(const C& c) -> decltype(c.rbegin()); // freestanding + template constexpr auto rend(C& c) -> decltype(c.rend()); // freestanding + template constexpr auto rend(const C& c) -> decltype(c.rend()); // freestanding + template constexpr reverse_iterator rbegin(T (&array)[N]) // freestanding + template constexpr reverse_iterator rend(T (&array)[N]); // freestanding + template constexpr reverse_iterator + rbegin(initializer_list il); // freestanding + template constexpr reverse_iterator + rend(initializer_list il); // freestanding + template constexpr auto + crbegin(const C& c) -> decltype(std::rbegin(c)); // freestanding + template constexpr auto + crend(const C& c) -> decltype(std::rend(c)); // freestanding + + template constexpr auto + size(const C& c) -> decltype(c.size()); // freestanding + template constexpr size_t + size(const T (&array)[N]) noexcept; // freestanding + + template constexpr auto + ssize(const C& c) + -> common_type_t>; // freestanding + template constexpr ptrdiff_t + ssize(const T (&array)[N]) noexcept; // freestanding + + template [[nodiscard]] constexpr auto + empty(const C& c) -> decltype(c.empty()); // freestanding + template [[nodiscard]] constexpr bool + empty(const T (&array)[N]) noexcept; // freestanding + template [[nodiscard]] constexpr bool + empty(initializer_list il) noexcept; // freestanding + + template constexpr auto data(C& c) -> decltype(c.data()); // freestanding + template constexpr auto data(const C& c) -> decltype(c.data()); // freestanding + template constexpr T* data(T (&array)[N]) noexcept; // freestanding + template constexpr const E* data(initializer_list il) noexcept; // freestanding } \end{codeblock} @@ -1242,16 +1291,12 @@ \begin{codeblock} template concept @\deflibconcept{indirectly_readable}@ = - @\placeholdernc{indirectly-readable-impl}@>; + @\exposconcept{indirectly-readable-impl}@>; \end{codeblock} \pnum Given a value \tcode{i} of type \tcode{I}, \tcode{I} models \libconcept{indirectly_readable} only if the expression \tcode{*i} is equality-preserving. -\begin{note} -The expression \tcode{*i} is indirectly required to be valid via the -exposition-only \exposconcept{dereferenceable} concept\iref{iterator.synopsis}. -\end{note} \rSec3[iterator.concept.writable]{Concept \cname{indirectly_writable}} @@ -2323,7 +2368,7 @@ \tcode{b - a} & \tcode{difference_type} & - \tcode{return n} & + \tcode{return n;} & \expects there exists a value \tcode{n} of type \tcode{difference_type} such that \tcode{a + n == b}.\br \tcode{b == a + (b - a)}. \\ \rowsep @@ -4110,6 +4155,547 @@ \tcode{insert_iterator(x, i)}. \end{itemdescr} +\rSec2[const.iterators]{Constant iterators and sentinels} + +\rSec3[const.iterators.general]{General} + +\pnum +Class template \tcode{basic_const_iterator} is an iterator adaptor +with the same behavior as the underlying iterator +except that its indirection operator implicitly converts +the value returned by the underlying iterator's indirection operator +to a type such that the adapted iterator is +a constant iterator\iref{iterator.requirements}. +Some generic algorithms can be called with constant iterators to avoid mutation. + +\pnum +Specializations of \tcode{basic_const_iterator} are constant iterators. + +\rSec3[const.iterators.alias]{Alias templates} + +\begin{itemdecl} +template<@\libconcept{indirectly_readable}@ It> + using iter_const_reference_t = + common_reference_t&&, iter_reference_t>; + +template + concept @\defexposconcept{constant-iterator}@ = // \expos + @\libconcept{input_iterator}@ && @\libconcept{same_as}@, iter_reference_t>; + +template<@\libconcept{input_iterator}@ I> + using @\libglobal{const_iterator}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +If \tcode{I} models \exposconcept{constant-iterator}, \tcode{I}. +Otherwise, \tcode{basic_const_iterator}. +\end{itemdescr} + +\begin{itemdecl} +template + using @\libglobal{const_sentinel}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\result +If \tcode{S} models \libconcept{input_iterator}, \tcode{const_iterator}. +Otherwise, \tcode{S}. +\end{itemdescr} + +\rSec3[const.iterators.iterator]{Class template \tcode{basic_const_iterator}} + +\begin{codeblock} +namespace std { + template + concept @\exposconcept{not-a-const-iterator}@ = @\seebelow@; + + template<@\libconcept{input_iterator}@ Iterator> + class @\libglobal{basic_const_iterator}@ { + Iterator @\exposidnc{current_}@ = Iterator(); // \expos + using @\exposidnc{reference}@ = iter_const_reference_t; // \expos + + public: + using iterator_concept = @\seebelow@; + using iterator_category = @\seebelow@; // not always present + using value_type = iter_value_t; + using difference_type = iter_difference_t; + + basic_const_iterator() requires @\libconcept{default_initializable}@ = default; + constexpr basic_const_iterator(Iterator current); + template<@\libconcept{convertible_to}@ U> + constexpr basic_const_iterator(basic_const_iterator current); + template<@\exposconcept{different-from}@ T> + requires @\libconcept{convertible_to}@ + constexpr basic_const_iterator(T&& current); + + constexpr const Iterator& base() const & noexcept; + constexpr Iterator base() &&; + + constexpr @\exposid{reference}@ operator*() const; + constexpr const value_type* operator->() const + requires is_lvalue_reference_v> && + @\libconcept{same_as}@>, value_type>; + + constexpr basic_const_iterator& operator++(); + constexpr void operator++(int); + constexpr basic_const_iterator operator++(int) requires @\libconcept{forward_iterator}@; + + constexpr basic_const_iterator& operator--() requires @\libconcept{bidirectional_iterator}@; + constexpr basic_const_iterator operator--(int) requires @\libconcept{bidirectional_iterator}@; + + constexpr basic_const_iterator& operator+=(difference_type n) + requires @\libconcept{random_access_iterator}@; + constexpr basic_const_iterator& operator-=(difference_type n) + requires @\libconcept{random_access_iterator}@; + + constexpr @\exposid{reference}@ operator[](difference_type n) const + requires @\libconcept{random_access_iterator}@; + + template<@\libconcept{sentinel_for}@ S> + friend constexpr bool operator==(const basic_const_iterator& x, const S& s); + + friend constexpr bool operator<(const basic_const_iterator& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; + friend constexpr bool operator>(const basic_const_iterator& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; + friend constexpr bool operator<=(const basic_const_iterator& x, + const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; + friend constexpr bool operator>=(const basic_const_iterator& x, + const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; + friend constexpr auto operator<=>(const basic_const_iterator& x, + const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{three_way_comparable}@; + + template<@\exposconcept{different-from}@ I> + friend constexpr bool operator<(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{different-from}@ I> + friend constexpr bool operator>(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{different-from}@ I> + friend constexpr bool operator<=(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{different-from}@ I> + friend constexpr bool operator>=(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator<(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator>(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator<=(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator>=(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; + template<@\exposconcept{different-from}@ I> + friend constexpr auto operator<=>(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@ && + @\libconcept{three_way_comparable_with}@; + + friend constexpr basic_const_iterator operator+(const basic_const_iterator& i, + difference_type n) + requires @\libconcept{random_access_iterator}@; + friend constexpr basic_const_iterator operator+(difference_type n, + const basic_const_iterator& i) + requires @\libconcept{random_access_iterator}@; + friend constexpr basic_const_iterator operator-(const basic_const_iterator& i, + difference_type n) + requires @\libconcept{random_access_iterator}@; + template<@\libconcept{sized_sentinel_for}@ S> + friend constexpr difference_type operator-(const basic_const_iterator& x, const S& y); + template<@\libconcept{sized_sentinel_for}@ S> + requires @\exposconcept{different-from}@ + friend constexpr difference_type operator-(const S& x, const basic_const_iterator& y); + }; +} +\end{codeblock} + +\pnum +Given some type \tcode{I}, +the concept \defexposconcept{not-a-const-iterator} is defined as \tcode{false} +if \tcode{I} is a specialization of \tcode{basic_const_iterator} and +\tcode{true} otherwise. + +\rSec3[const.iterators.types]{Member types} + +\pnum +\tcode{basic_const_iterator::iterator_concept} is defined as follows: +\begin{itemize} +\item +If \tcode{Iterator} models \libconcept{contiguous_iterator}, +then \tcode{iterator_concept} denotes \tcode{contiguous_iterator_tag}. +\item +Otherwise, if \tcode{Iterator} models \libconcept{random_access_iterator}, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, if \tcode{Iterator} models \libconcept{bidirectional_iterator}, +then \tcode{iterator_concept} denotes \tcode{bidirec\-tional_iterator_tag}. +\item +Otherwise, if \tcode{Iterator} models \libconcept{forward_iterator}, +then \tcode{iterator_concept} denotes \tcode{forward_itera\-tor_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 \tcode{Iterator} models \libconcept{forward_iterator}. +In that case, +\tcode{basic_const_iterator::iterator_category} denotes +the type \tcode{iterator_traits<\brk{}Iterator>::iterator_category}. + +\rSec3[const.iterators.ops]{Operations} + +\indexlibraryctor{basic_const_iterator}% +\begin{itemdecl} +constexpr basic_const_iterator(Iterator current); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(current)}. +\end{itemdescr} + +\indexlibraryctor{basic_const_iterator}% +\begin{itemdecl} +template<@\libconcept{convertible_to}@ U> + constexpr basic_const_iterator(basic_const_iterator current); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} +with \tcode{std::move(current.\exposid{current_})}. +\end{itemdescr} + +\indexlibraryctor{basic_const_iterator}% +\begin{itemdecl} +template<@\exposconcept{different-from}@ T> + requires @\libconcept{convertible_to}@ + constexpr basic_const_iterator(T&& current); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::forward(current)}. +\end{itemdescr} + +\indexlibrarymember{base}{basic_const_iterator}% +\begin{itemdecl} +constexpr const Iterator& base() const & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{base}{basic_const_iterator}% +\begin{itemdecl} +constexpr Iterator base() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return std::move(\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{operator*}{basic_const_iterator}% +\begin{itemdecl} +constexpr @\exposid{reference}@ operator*() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return static_cast<\exposid{reference}>(*\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{operator->}{basic_const_iterator}% +\begin{itemdecl} +constexpr const value_type* operator->() const + requires is_lvalue_reference_v> && + @\libconcept{same_as}@>, value_type>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{Iterator} models \libconcept{contiguous_iterator}, +\tcode{to_address(\exposid{current_})}; +otherwise, \tcode{address\-of(*\exposid{current_})}. +\end{itemdescr} + +\indexlibrarymember{operator++}{basic_const_iterator}% +\begin{itemdecl} +constexpr basic_const_iterator& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +++@\exposid{current_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{basic_const_iterator}% +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{++\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator++}{basic_const_iterator}% +\begin{itemdecl} +constexpr basic_const_iterator operator++(int) requires @\libconcept{forward_iterator}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{basic_const_iterator}% +\begin{itemdecl} +constexpr basic_const_iterator& operator--() requires @\libconcept{bidirectional_iterator}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +--@\exposid{current_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{basic_const_iterator}% +\begin{itemdecl} +constexpr basic_const_iterator operator--(int) requires @\libconcept{bidirectional_iterator}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +--*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+=}{basic_const_iterator}% +\indexlibrarymember{operator-=}{basic_const_iterator}% +\begin{itemdecl} +constexpr basic_const_iterator& operator+=(difference_type n) + requires @\libconcept{random_access_iterator}@; +constexpr basic_const_iterator& operator-=(difference_type n) + requires @\libconcept{random_access_iterator}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{op}} be the operator. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ @\placeholder{op}@ n; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator[]}{basic_const_iterator}% +\begin{itemdecl} +constexpr @\exposid{reference}@ operator[](difference_type n) const requires @\libconcept{random_access_iterator}@ +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return static_cast<\exposid{reference}>(\exposid{current_}[n]);} +\end{itemdescr} + +\indexlibrarymember{operator==}{basic_const_iterator}% +\begin{itemdecl} +template<@\libconcept{sentinel_for}@ S> + friend constexpr bool operator==(const basic_const_iterator& x, const S& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} == s;} +\end{itemdescr} + +\indexlibrarymember{operator<}{basic_const_iterator}% +\indexlibrarymember{operator>}{basic_const_iterator}% +\indexlibrarymember{operator<=}{basic_const_iterator}% +\indexlibrarymember{operator>=}{basic_const_iterator}% +\indexlibrarymember{operator<=>}{basic_const_iterator}% +\begin{itemdecl} +friend constexpr bool operator<(const basic_const_iterator& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; +friend constexpr bool operator>(const basic_const_iterator& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; +friend constexpr bool operator<=(const basic_const_iterator& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; +friend constexpr bool operator>=(const basic_const_iterator& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@; +friend constexpr auto operator<=>(const basic_const_iterator& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{three_way_comparable}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{op}} be the operator. + +\pnum +\effects +Equivalent to: +\tcode{return x.\exposid{current_} \placeholder{op} \exposid{y.current_};} +\end{itemdescr} + +\indexlibrarymember{operator<}{basic_const_iterator}% +\indexlibrarymember{operator>}{basic_const_iterator}% +\indexlibrarymember{operator<=}{basic_const_iterator}% +\indexlibrarymember{operator>=}{basic_const_iterator}% +\indexlibrarymember{operator<=>}{basic_const_iterator}% +\begin{itemdecl} +template<@\exposconcept{different-from}@ I> + friend constexpr bool operator<(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +template<@\exposconcept{different-from}@ I> + friend constexpr bool operator>(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +template<@\exposconcept{different-from}@ I> + friend constexpr bool operator<=(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +template<@\exposconcept{different-from}@ I> + friend constexpr bool operator>=(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +template<@\exposconcept{different-from}@ I> + friend constexpr auto operator<=>(const basic_const_iterator& x, const I& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@ && + @\libconcept{three_way_comparable_with}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{op}} be the operator. + +\pnum +\returns +Equivalent to: \tcode{return x.\exposid{current_} \placeholder{op} y;} +\end{itemdescr} + +\indexlibrarymember{operator<}{basic_const_iterator}% +\indexlibrarymember{operator>}{basic_const_iterator}% +\indexlibrarymember{operator<=}{basic_const_iterator}% +\indexlibrarymember{operator>=}{basic_const_iterator}% +\begin{itemdecl} +template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator<(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator>(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator<=(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +template<@\exposconcept{not-a-const-iterator}@ I> + friend constexpr bool operator>=(const I& x, const basic_const_iterator& y) + requires @\libconcept{random_access_iterator}@ && @\libconcept{totally_ordered_with}@; +\end{itemdecl} + +\begin{itemdescr} +Let \tcode{\placeholder{op}} be the operator. + +\pnum +\returns +Equivalent to: \tcode{return x \placeholder{op} y.\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator+}{basic_const_iterator}% +\begin{itemdecl} +friend constexpr basic_const_iterator operator+(const basic_const_iterator& i, difference_type n) + requires @\libconcept{random_access_iterator}@; +friend constexpr basic_const_iterator operator+(difference_type n, const basic_const_iterator& i) + requires @\libconcept{random_access_iterator}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return basic_const_iterator(i.\exposid{current_} + n);} +\end{itemdescr} + +\indexlibrarymember{operator-}{basic_const_iterator}% +\begin{itemdecl} +friend constexpr basic_const_iterator operator-(const basic_const_iterator& i, difference_type n) + requires @\libconcept{random_access_iterator}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return basic_const_iterator(i.\exposid{current_} - n);} +\end{itemdescr} + +\indexlibrarymember{operator-}{basic_const_iterator}% +\begin{itemdecl} +template<@\libconcept{sized_sentinel_for}@ S> + friend constexpr difference_type operator-(const basic_const_iterator& x, const S& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{current_} - y;} +\end{itemdescr} + +\indexlibrarymember{operator-}{basic_const_iterator}% +\begin{itemdecl} +template<@\libconcept{sized_sentinel_for}@ S> + requires @\exposconcept{different-from}@ + friend constexpr difference_type operator-(const S& x, const basic_const_iterator& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x - y.\exposid{current_};} +\end{itemdescr} + \rSec2[move.iterators]{Move iterators and sentinels} \rSec3[move.iterators.general]{General} @@ -4143,7 +4729,7 @@ class move_iterator { public: using iterator_type = Iterator; - using iterator_concept = input_iterator_tag; + using iterator_concept = @\seebelow@; using iterator_category = @\seebelow@; // not always present using value_type = iter_value_t; using difference_type = iter_difference_t; @@ -4193,6 +4779,23 @@ } \end{codeblock} +\pnum +The member \grammarterm{typedef-name} \tcode{iterator_concept} is defined +as follows: +\begin{itemize} +\item +If \tcode{Iterator} models \libconcept{random_access_iterator}, +then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. +\item +Otherwise, if \tcode{Iterator} models \libconcept{bidirectional_iterator}, +then \tcode{iterator_concept} denotes \tcode{bidirec\-tional_iterator_tag}. +\item +Otherwise, if \tcode{Iterator} models \libconcept{forward_iterator}, +then \tcode{iterator_concept} denotes \tcode{forward_itera\-tor_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 the \grammarterm{qualified-id} @@ -4283,6 +4886,10 @@ \effects Assigns \tcode{u.current} to \tcode{current}. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} \rSec3[move.iter.op.conv]{Conversion} @@ -4646,13 +5253,12 @@ \begin{example} A \tcode{move_if} algorithm is easily implemented with \tcode{copy_if} using \tcode{move_iterator} and \tcode{move_sentinel}: - \begin{codeblock} template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S, @\libconcept{weakly_incrementable}@ O, @\libconcept{indirect_unary_predicate}@ Pred> requires @\libconcept{indirectly_movable}@ void move_if(I first, S last, O out, Pred pred) { - std::ranges::copy_if(move_iterator{first}, move_sentinel{last}, out, pred); + ranges::copy_if(move_iterator{first}, move_sentinel{last}, out, pred); } \end{codeblock} \end{example} @@ -4796,7 +5402,7 @@ constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const requires @\exposconcept{dereferenceable}@; - constexpr decltype(auto) operator->() const + constexpr auto operator->() const requires @\seebelow@; constexpr common_iterator& operator++(); @@ -4964,7 +5570,7 @@ \indexlibrarymember{operator->}{common_iterator}% \begin{itemdecl} -constexpr decltype(auto) operator->() const +constexpr auto operator->() const requires @\seebelow@; \end{itemdecl} @@ -5528,8 +6134,8 @@ \indexlibrarymember{operator--}{counted_iterator}% \begin{itemdecl} - constexpr counted_iterator& operator--() - requires @\libconcept{bidirectional_iterator}@; +constexpr counted_iterator& operator--() + requires @\libconcept{bidirectional_iterator}@; \end{itemdecl} \begin{itemdescr} @@ -5545,8 +6151,8 @@ \indexlibrarymember{operator--}{counted_iterator}% \begin{itemdecl} - constexpr counted_iterator operator--(int) - requires @\libconcept{bidirectional_iterator}@; +constexpr counted_iterator operator--(int) + requires @\libconcept{bidirectional_iterator}@; \end{itemdecl} \begin{itemdescr} @@ -5562,8 +6168,8 @@ \indexlibrarymember{operator+}{counted_iterator}% \begin{itemdecl} - constexpr counted_iterator operator+(iter_difference_t n) const - requires @\libconcept{random_access_iterator}@; +constexpr counted_iterator operator+(iter_difference_t n) const + requires @\libconcept{random_access_iterator}@; \end{itemdecl} \begin{itemdescr} @@ -5587,8 +6193,8 @@ \indexlibrarymember{operator+=}{counted_iterator}% \begin{itemdecl} - constexpr counted_iterator& operator+=(iter_difference_t n) - requires @\libconcept{random_access_iterator}@; +constexpr counted_iterator& operator+=(iter_difference_t n) + requires @\libconcept{random_access_iterator}@; \end{itemdecl} \begin{itemdescr} @@ -5608,8 +6214,8 @@ \indexlibrarymember{operator-}{counted_iterator}% \begin{itemdecl} - constexpr counted_iterator operator-(iter_difference_t n) const - requires @\libconcept{random_access_iterator}@; +constexpr counted_iterator operator-(iter_difference_t n) const + requires @\libconcept{random_access_iterator}@; \end{itemdecl} \begin{itemdescr} @@ -6225,6 +6831,7 @@ using streambuf_type = basic_streambuf; using istream_type = basic_istream; + // \ref{istreambuf.iterator.proxy}, class \tcode{istreambuf_iterator::\exposid{proxy}} class @\placeholder{proxy}@; // \expos constexpr istreambuf_iterator() noexcept; diff --git a/source/lex.tex b/source/lex.tex index 77e09e142a..0f33bfda64 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -67,14 +67,33 @@ \item \indextext{character!source file}% \indextext{character set!basic source}% -Physical source file characters are mapped, in an +An implementation shall support input files +that are a sequence of UTF-8 code units (UTF-8 files). +It may also support +an \impldef{supported input files} set of other kinds of input files, and, +if so, the kind of an input file is determined in +an \impldef{determination of kind of input file} manner +that includes a means of designating input files as UTF-8 files, +independent of their content. +\begin{note} +In other words, +recognizing the \unicode{feff}{byte order mark} is not sufficient. +\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 UCS scalar values +that constitutes the sequence of elements of the translation character set. + +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 the translation character set\iref{lex.charset} +to a sequence of translation character set elements\iref{lex.charset} (introducing new-line characters for end-of-line indicators). -The set of physical source file characters accepted is \impldef{physical source file -characters}. + \item \indextext{line splicing}% +If the first translation character is \unicode{feff}{byte order mark}, +it is deleted. Each sequence of a backslash character (\textbackslash) immediately followed by zero or more whitespace characters other than new-line followed by @@ -288,23 +307,171 @@ The \grammarterm{universal-character-name} construct provides a way to name other characters. +\begin{bnf} +\nontermdef{n-char} \textnormal{one of}\br + \terminal{A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}\br + \terminal{0 1 2 3 4 5 6 7 8 9}\br + \textnormal{\unicode{002d}{hyphen-minus}}\br + \textnormal{\unicode{0020}{space}} +\end{bnf} + +\begin{bnf} +\nontermdef{n-char-sequence}\br + n-char\br + n-char-sequence n-char +\end{bnf} + +\begin{bnf} +\nontermdef{named-universal-character}\br + \terminal{\textbackslash N\{} n-char-sequence \terminal{\}} +\end{bnf} + \begin{bnf} \nontermdef{hex-quad}\br hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit \end{bnf} +\begin{bnf} +\nontermdef{simple-hexadecimal-digit-sequence}\br + hexadecimal-digit\br + simple-hexadecimal-digit-sequence hexadecimal-digit +\end{bnf} + \begin{bnf} \nontermdef{universal-character-name}\br \terminal{\textbackslash u} hex-quad\br - \terminal{\textbackslash U} hex-quad hex-quad + \terminal{\textbackslash U} hex-quad hex-quad\br + \terminal{\textbackslash u\{} simple-hexadecimal-digit-sequence \terminal{\}}\br + named-universal-character \end{bnf} +\pnum A \grammarterm{universal-character-name} +of the form \tcode{\textbackslash u} \grammarterm{hex-quad}, +\tcode{\textbackslash U} \grammarterm{hex-quad} \grammarterm{hex-quad}, or +\tcode{\textbackslash u\{\grammarterm{simple-hexadecimal-digit-sequence}\}} designates the character in the translation character set whose UCS scalar value is the hexadecimal number represented by the sequence of \grammarterm{hexadecimal-digit}s in the \grammarterm{universal-character-name}. The program is ill-formed if that number is not a UCS scalar value. + +\pnum +A \grammarterm{universal-character-name} +that is a \grammarterm{named-universal-character} +designates the character named by its \grammarterm{n-char-sequence}. +A character is so named if the \grammarterm{n-char-sequence} is equal to +\begin{itemize} +\item +the associated character name or associated character name alias +specified in ISO/IEC 10646 subclause ``Code charts and lists of character names'' +or +\item +the control code alias given in \tref{lex.charset.ucn}. +\begin{note} +The aliases in \tref{lex.charset.ucn} are provided for control characters +which otherwise have no associated character name or character name alias. +These names are derived from +the Unicode Character Database's \tcode{NameAliases.txt}. +For historical reasons, control characters are formally unnamed. +\end{note} +\end{itemize} +\begin{note} +None of the associated character names, +associated character name aliases, or +control code aliases +have leading or trailing spaces. +\end{note} + +\begin{multicolfloattable}{Control code aliases}{lex.charset.ucn}{ll} +\unicode{0000}{null} \\ +\unicode{0001}{start of heading} \\ +\unicode{0002}{start of text} \\ +\unicode{0003}{end of text} \\ +\unicode{0004}{end of transmission} \\ +\unicode{0005}{enquiry} \\ +\unicode{0006}{acknowledge} \\ +\unicode{0007}{alert} \\ +\unicode{0008}{backspace} \\ +\unicode{0009}{character tabulation} \\ +\unicode{0009}{horizontal tabulation} \\ +\unicode{000a}{line feed} \\ +\unicode{000a}{new line} \\ +\unicode{000a}{end of line} \\ +\unicode{000b}{line tabulation} \\ +\unicode{000b}{vertical tabulation} \\ +\unicode{000c}{form feed} \\ +\unicode{000d}{carriage return} \\ +\unicode{000e}{shift out} \\ +\unicode{000e}{locking-shift one} \\ +\unicode{000f}{shift in} \\ +\unicode{000f}{locking-shift zero} \\ +\unicode{0010}{data link escape} \\ +\unicode{0011}{device control one} \\ +\unicode{0012}{device control two} \\ +\unicode{0013}{device control three} \\ +\unicode{0014}{device control four} \\ +\unicode{0015}{negative acknowledge} \\ +\unicode{0016}{synchronous idle} \\ +\unicode{0017}{end of transmission block} \\ +\unicode{0018}{cancel} \\ +\unicode{0019}{end of medium} \\ +\unicode{001a}{substitute} \\ +\unicode{001b}{escape} \\ +\unicode{001c}{information separator four} \\ +\unicode{001c}{file separator} \\ +\unicode{001d}{information separator three} \\ +\unicode{001d}{group separator} \\ +\unicode{001e}{information separator two} \\ +\unicode{001e}{record separator} \\ +\unicode{001f}{information separator one} \\ +\unicode{001f}{unit separator} \\ +\columnbreak +\unicode{007f}{delete} \\ +\unicode{0082}{break permitted here} \\ +\unicode{0083}{no break here} \\ +\unicode{0084}{index} \\ +\unicode{0085}{next line} \\ +\unicode{0086}{start of selected area} \\ +\unicode{0087}{end of selected area} \\ +\unicode{0088}{character tabulation set} \\ +\unicode{0088}{horizontal tabulation set} \\ +\unicode{0089}{character tabulation with justification} \\ +\unicode{0089}{horizontal tabulation with justification} \\ +\unicode{008a}{line tabulation set} \\ +\unicode{008a}{vertical tabulation set} \\ +\unicode{008b}{partial line forward} \\ +\unicode{008b}{partial line down} \\ +\unicode{008c}{partial line backward} \\ +\unicode{008c}{partial line up} \\ +\unicode{008d}{reverse line feed} \\ +\unicode{008d}{reverse index} \\ +\unicode{008e}{single shift two} \\ +\unicode{008e}{single-shift-2} \\ +\unicode{008f}{single shift three} \\ +\unicode{008f}{single-shift-3} \\ +\unicode{0090}{device control string} \\ +\unicode{0091}{private use one} \\ +\unicode{0091}{private use-1} \\ +\unicode{0092}{private use two} \\ +\unicode{0092}{private use-2} \\ +\unicode{0093}{set transmit state} \\ +\unicode{0094}{cancel character} \\ +\unicode{0095}{message waiting} \\ +\unicode{0096}{start of guarded area} \\ +\unicode{0096}{start of protected area} \\ +\unicode{0097}{end of guarded area} \\ +\unicode{0097}{end of protected area} \\ +\unicode{0098}{start of string} \\ +\unicode{009a}{single character introducer} \\ +\unicode{009b}{control sequence introducer} \\ +\unicode{009c}{string terminator} \\ +\unicode{009d}{operating system command} \\ +\unicode{009e}{privacy message} \\ +\unicode{009f}{application program command} \\ +\end{multicolfloattable} + +\pnum If a \grammarterm{universal-character-name} outside the \grammarterm{c-char-sequence}, \grammarterm{s-char-sequence}, or \grammarterm{r-char-sequence} of @@ -712,7 +879,7 @@ \begin{bnf} \nontermdef{identifier}\br identifier-start\br - identifier identifier-continue\br + identifier identifier-continue \end{bnf} \begin{bnf} @@ -1310,17 +1477,25 @@ hexadecimal-escape-sequence \end{bnf} +\begin{bnf} +\nontermdef{simple-octal-digit-sequence}\br + octal-digit\br + simple-octal-digit-sequence octal-digit +\end{bnf} + \begin{bnf} \nontermdef{octal-escape-sequence}\br \terminal{\textbackslash} octal-digit\br \terminal{\textbackslash} octal-digit octal-digit\br - \terminal{\textbackslash} octal-digit octal-digit octal-digit + \terminal{\textbackslash} octal-digit octal-digit octal-digit\br + \terminal{\textbackslash o\{} simple-octal-digit-sequence \terminal{\}}\br \end{bnf} \begin{bnf} \nontermdef{hexadecimal-escape-sequence}\br \terminal{\textbackslash x} hexadecimal-digit\br - hexadecimal-escape-sequence hexadecimal-digit + hexadecimal-escape-sequence hexadecimal-digit\br + \terminal{\textbackslash x\{} simple-hexadecimal-digit-sequence \terminal{\}} \end{bnf} \begin{bnf} @@ -1330,7 +1505,7 @@ \begin{bnf} \nontermdef{conditional-escape-sequence-char}\br - \textnormal{any member of the basic character set that is not an} octal-digit\textnormal{, a} simple-escape-sequence-char\textnormal{, or the characters \terminal{u}, \terminal{U}, or \terminal{x}} + \textnormal{any member of the basic character set that is not an} octal-digit\textnormal{, a} simple-escape-sequence-char\textnormal{, or the characters \terminal{N}, \terminal{o}, \terminal{u}, \terminal{U}, or \terminal{x}} \end{bnf} \pnum @@ -1356,7 +1531,7 @@ more than one \grammarterm{c-char}. The \grammarterm{encoding-prefix} of a non-encodable character literal or a multicharacter literal -shall be absent or \tcode{L}. +shall be absent. Such \grammarterm{character-literal}s are conditionally-supported. \pnum @@ -1367,17 +1542,17 @@ as defined by \tref{lex.ccon.literal}. The special cases for non-encodable character literals and multicharacter literals -take precedence over their respective base kinds. +take precedence over the base kind. \begin{note} -The associated character encoding for ordinary and wide character literals +The associated character encoding for ordinary character literals determines encodability, but does not determine the value of -non-encodable ordinary or wide character literals or -ordinary or wide multicharacter literals. +non-encodable ordinary character literals or +ordinary multicharacter literals. The examples in \tref{lex.ccon.literal} -for non-encodable ordinary and wide character literals assume that +for non-encodable ordinary character literals assume that the specified character lacks representation in -the ordinary literal encoding or wide literal encoding, respectively, or +the ordinary literal encoding or that encoding the character would require more than one code unit. \end{note} @@ -1405,18 +1580,9 @@ \tcode{L} & \defnx{wide character literal}{literal!character!wide} & \keyword{wchar_t} & -wide & -\tcode{L'w'} \\ \cline{2-3}\cline{5-5} - & -non-encodable wide character literal & -\keyword{wchar_t} & -literal & -\tcode{L'\textbackslash U0001F32A'} \\ \cline{2-3}\cline{5-5} - & -wide multicharacter literal & -\keyword{wchar_t} & -encoding & -\tcode{L'abcd'} \\ \hline +wide literal & +\tcode{L'w'} \\ + & & & encoding & \\ \hline \tcode{u8} & \defnx{UTF-8 character literal}{literal!character!UTF-8} & \keyword{char8_t} & @@ -1464,9 +1630,17 @@ A \grammarterm{character-literal} with a \grammarterm{c-char-sequence} consisting of a single \grammarterm{numeric-escape-sequence} -that specifies an integer value $v$ has a value as follows: +has a value as follows: \begin{itemize} \item +Let $v$ be the integer value represented by +the octal number comprising +the sequence of \grammarterm{octal-digit}{s} in +an \grammarterm{octal-escape-sequence} or by +the hexadecimal number comprising +the sequence of \grammarterm{hexadecimal-digit}{s} in +a \grammarterm{hexadecimal-escape-sequence}. +\item If $v$ does not exceed the range of representable values of the \grammarterm{character-literal}'s type, then the value is $v$. @@ -1511,7 +1685,7 @@ \ucode{0007} & \uname{alert} & \tcode{\textbackslash a} \\ \ucode{005c} & \uname{reverse solidus} & \tcode{\textbackslash\textbackslash} \\ \ucode{003f} & \uname{question mark} & \tcode{\textbackslash ?} \\ -\ucode{0027} & \uname{apostrohpe} & \tcode{\textbackslash '} \\ +\ucode{0027} & \uname{apostrophe} & \tcode{\textbackslash '} \\ \ucode{0022} & \uname{quotation mark} & \tcode{\textbackslash "} \\ \end{floattable} @@ -1573,7 +1747,7 @@ \begin{bnf} \nontermdef{floating-point-suffix} \textnormal{one of}\br - \terminal{f l F L} + \terminal{f l f16 f32 f64 f128 bf16 F L F16 F32 F64 F128 BF16} \end{bnf} \pnum @@ -1584,8 +1758,16 @@ \indextext{suffix!\idxcode{L}}% \indextext{suffix!\idxcode{l}}% \indextext{literal!\idxcode{long double}}% -The type of a \grammarterm{floating-point-literal} is determined by +The type of +a \grammarterm{floating-point-literal}\iref{basic.fundamental,basic.extended.fp} +is determined by its \grammarterm{floating-point-suffix} as specified in \tref{lex.fcon.type}. +\begin{note} +The floating-point suffixes +\tcode{f16}, \tcode{f32}, \tcode{f64}, \tcode{f128}, \tcode{bf16}, +\tcode{F16}, \tcode{F32}, \tcode{F64}, \tcode{F128}, and \tcode{BF16} +are conditionally-supported. See \ref{basic.extended.fp}. +\end{note} \begin{simpletypetable} {Types of \grammarterm{floating-point-literal}{s}} {lex.fcon.type} @@ -1595,6 +1777,11 @@ none & \keyword{double} \\ \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} \\ +\tcode{f64} or \tcode{F64} & \tcode{std::float64_t} \\ +\tcode{f128} or \tcode{F128} & \tcode{std::float128_t} \\ +\tcode{bf16} or \tcode{BF16} & \tcode{std::bfloat16_t} \\ \end{simpletypetable} \pnum @@ -1922,10 +2109,17 @@ \end{note} \item Each \grammarterm{numeric-escape-sequence}\iref{lex.ccon} -that specifies an integer value $v$ contributes a single code unit with a value as follows: \begin{itemize} \item +Let $v$ be the integer value represented by +the octal number comprising +the sequence of \grammarterm{octal-digit}{s} in +an \grammarterm{octal-escape-sequence} or by +the hexadecimal number comprising +the sequence of \grammarterm{hexadecimal-digit}{s} in +a \grammarterm{hexadecimal-escape-sequence}. +\item If $v$ does not exceed the range of representable values of the \grammarterm{string-literal}'s array element type, then the value is $v$. diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 04ada51d52..590670d176 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -492,9 +492,11 @@ \indexlibrary{decay-copy@\tcode{\placeholder{decay-copy}}}% \begin{codeblock} namespace std { - template constexpr decay_t @\placeholdernc{decay-copy}@(T&& v) - noexcept(is_nothrow_convertible_v>) // \expos - { return std::forward(v); } + template + requires @\libconcept{convertible_to}@> + constexpr decay_t @\placeholdernc{decay-copy}@(T&& v) + noexcept(is_nothrow_convertible_v>) // \expos + { return std::forward(v); } constexpr auto @\placeholdernc{synth-three-way}@ = [](const T& t, const U& u) @@ -564,7 +566,7 @@ \pnum Several types defined in \ref{input.output} are -\defnx{enumerated types}{type!enumerated}. +\defnadjx{enumerated}{types}{type}. Each enumerated type may be implemented as an enumeration or as a synonym for an enumeration. \begin{footnote} @@ -698,6 +700,8 @@ are supersets of the basic literal character set\iref{lex.charset}. The encodings of the execution character sets and the sets of additional elements (if any) are locale-specific. +Each element of the execution wide-character set is encoded as +a single code unit representable by a value of type \keyword{wchar_t}. \begin{note} The encodings of the execution character sets can be unrelated to any literal encoding. @@ -904,6 +908,52 @@ \pnum An implementation may use any technique that provides equivalent observable behavior. +\rSec3[freestanding.entity]{Freestanding entities} + +\pnum +\indextext{entity!freestanding|see{freestanding entity}}% +A \defn{freestanding entity} is a declaration or macro definition +that is present in a freestanding implementation and a hosted implementation. + +\pnum +Unless otherwise specified, +the requirements on freestanding entities on a freestanding implementation +are the same as the corresponding requirements in a hosted implementation. + +\pnum +In a header synopsis, entities followed with a comment +that includes \textit{freestanding} are freestanding entities. +\begin{example} +\begin{codeblock} +#define NULL @\seebelow@ // freestanding +\end{codeblock} +\end{example} + +\pnum +If a header synopsis begins with a comment +that includes \textit{all freestanding}, +then all of the declarations and macro definitions in the header synopsis +are freestanding entities. +\begin{example} +\begin{codeblock} +// all freestanding +namespace std { +\end{codeblock} +\end{example} + +\pnum +Deduction guides for freestanding entity class templates are freestanding entities. + +\pnum +Enclosing namespaces of freestanding entities are freestanding entities. + +\pnum +Friends of freestanding entities are freestanding entities. + +\pnum +Entities denoted by freestanding entity \grammarterm{typedef-name}{s} and +freestanding entity alias templates are freestanding entities. + \rSec1[requirements]{Library-wide requirements} \rSec2[requirements.general]{General} @@ -1030,11 +1080,14 @@ \tcode{} \\ \tcode{} \\ \columnbreak +\tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1047,6 +1100,7 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1056,6 +1110,7 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1073,6 +1128,7 @@ \tcode{} \\ \columnbreak \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1308,6 +1364,62 @@ \tcode{wscanf_s} \\ \end{multicolfloattable} +\rSec3[std.modules]{Modules} + +\pnum +The \Cpp{} standard library provides +the following \defn{\Cpp{} library modules}. + +\pnum +The named module \tcode{std} exports declarations in namespace \tcode{std} +that are provided by the importable \Cpp{} library headers +(\tref{headers.cpp} or the subset provided by a freestanding implementation) +and the \Cpp{} headers for C library facilities~(\tref{headers.cpp.c}). +It additionally exports declarations in the global namespace +for the storage allocation and deallocation functions +that are provided by \libheaderref{new}. + +\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 +corresponding to the declarations in namespace \tcode{std} +that are provided by +the \Cpp{} headers for C library facilities~(\tref{headers.cpp.c}). + +\pnum +It is unspecified to which module a declaration in the standard library +is attached. +\begin{note} +Implementations are required to ensure that mixing +\tcode{\#include} and \tcode{import} does not result in +conflicting attachments\iref{basic.link}. +\end{note} +\recommended +Implementations should ensure such attachments do not preclude +further evolution or decomposition of the standard library modules. + +\pnum +A declaration in the standard library denotes the same entity regardless of +whether it was made reachable through +including a header, +importing a header unit, or +importing a \Cpp{} library module. + +\pnum +\recommended +Implementations should avoid exporting any other declarations +from the \Cpp{} library modules. + +\begin{note} +Like all named modules, the \Cpp{} library modules +do not make macros visible\iref{module.import}, such as +\tcode{assert}\iref{cassert.syn}, +\tcode{errno}\iref{cerrno.syn}, +\tcode{offsetof}\iref{cstddef.syn}, and +\tcode{va_arg}\iref{cstdarg.syn}. +\end{note} + \rSec3[compliance]{Freestanding implementations} \indextext{implementation!freestanding|(}% @@ -1342,38 +1454,31 @@ \ref{concepts} & Concepts library & \tcode{} \\ \rowsep \ref{type.traits} & Type traits & \tcode{} \\ \rowsep \ref{bit} & Bit manipulation & \tcode{} \\ \rowsep -\ref{atomics} & Atomics & \tcode{} \\ +\ref{atomics} & Atomics & \tcode{} \\ \rowsep +\ref{utility} & Utility components & \tcode{} \\ \rowsep +\ref{tuple} & Tuples & \tcode{} \\ \rowsep +\ref{memory} & Memory & \tcode{} \\ \rowsep +\ref{function.objects} & Function objects & \tcode{} \\ \rowsep +\ref{ratio} & Compile-time rational arithmetic & \tcode{} \\ \rowsep +\ref{iterators} & Iterators library & \tcode{} \\ \rowsep +\ref{ranges} & Ranges library & \tcode{} \\ \end{libsumtab} \pnum -The supplied version of the header \libheaderref{cstdlib} -shall declare at least the functions -\indexlibraryglobal{abort}% -\tcode{abort}, -\indexlibraryglobal{atexit}% -\tcode{atexit}, -\indexlibraryglobal{at_quick_exit}% -\tcode{at_quick_exit}, -\indexlibraryglobal{exit}% -\tcode{exit}, -and -\indexlibraryglobal{quick_exit}% -\tcode{quick_exit}\iref{support.start.term}. -\indextext{implementation!hosted}% -The supplied version of the header \libheaderrefx{atomic}{atomics.syn} -shall meet the same requirements as for a hosted implementation -except that support for -always lock-free integral atomic types\iref{atomics.lockfree} -is \impldef{support for always lock-free integral atomic types in -freestanding environments}, and -whether or not the type aliases \tcode{atomic_signed_lock_free} and -\tcode{atomic_unsigned_lock_free} are defined\iref{atomics.alias} -is \impldef{type aliases \tcode{atomic_signed_lock_free} and -\tcode{atomic_unsigned_lock_free} in freestanding environments}. -The other headers listed in this table -shall meet the same requirements as for a hosted implementation. +For each of the headers listed in \tref{headers.cpp.fs}, +a freestanding implementation provides at least +the freestanding entities\iref{freestanding.entity} declared in the header. \indextext{implementation!freestanding|)}% +\pnum +\begin{note} +Throwing a standard library provided exception +is not observably different from \tcode{terminate()} +if the implementation does not +unwind the stack during exception handling\iref{except.handle} and +the user's program contains no catch blocks. +\end{note} + \rSec2[using]{Using the library} \rSec3[using.overview]{Overview} @@ -2464,7 +2569,7 @@ \end{itemdescr} \begin{itemdecl} -X::propagate_on_container_copy_assignment +typename X::propagate_on_container_copy_assignment \end{itemdecl} \begin{itemdescr} @@ -2486,7 +2591,7 @@ \end{itemdescr} \begin{itemdecl} -X::propagate_on_container_move_assignment +typename X::propagate_on_container_move_assignment \end{itemdecl} \begin{itemdescr} @@ -2508,7 +2613,7 @@ \end{itemdescr} \begin{itemdecl} -X::propagate_on_container_swap +typename X::propagate_on_container_swap \end{itemdecl} \begin{itemdescr} @@ -2530,7 +2635,7 @@ \end{itemdescr} \begin{itemdecl} -X::is_always_equal +typename X::is_always_equal \end{itemdecl} \begin{itemdescr} @@ -2624,21 +2729,18 @@ interface that meets the requirements of \ref{allocator.requirements.general}: \begin{codeblock} -template +template struct SimpleAllocator { - typedef Tp value_type; + using value_type = T; SimpleAllocator(@\textit{ctor args}@); - template SimpleAllocator(const SimpleAllocator& other); + template SimpleAllocator(const SimpleAllocator& other); - [[nodiscard]] Tp* allocate(std::size_t n); - void deallocate(Tp* p, std::size_t n); -}; + [[nodiscard]] T* allocate(std::size_t n); + void deallocate(T* p, std::size_t n); -template -bool operator==(const SimpleAllocator&, const SimpleAllocator&); -template -bool operator!=(const SimpleAllocator&, const SimpleAllocator&); + bool operator==(const SimpleAllocator&) const; +}; \end{codeblock} \end{example} @@ -3172,7 +3274,7 @@ on the implementation. \pnum -In particular, the effects are undefined in the following cases: +In particular, the behavior is undefined in the following cases: \begin{itemize} \item diff --git a/source/locales.tex b/source/locales.tex index e0533f7d71..788abc1be0 100644 --- a/source/locales.tex +++ b/source/locales.tex @@ -1655,7 +1655,7 @@ \indextext{UTF-32}% The specialization \tcode{codecvt} converts between the UTF-16 and UTF-8 encoding forms, and -the specialization \tcode{codecvt} \tcode{} +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. @@ -3014,7 +3014,7 @@ The specializations required in \tref{locale.category.facets}\iref{locale.category}, namely \tcode{collate} and \tcode{collate}, -apply lexicographic ordering\iref{alg.lex.comparison}. +apply lexicographical ordering\iref{alg.lex.comparison}. \pnum Each function compares a string of characters \tcode{*p} diff --git a/source/macros.tex b/source/macros.tex index 84f6ecbf71..295267bf98 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -147,6 +147,8 @@ \let\textup\nocode% \let\otcode\tcode% \let\tcode\nocode% +\let\oexposid\exposid% +\let\exposid\nocode% \let\ogrammarterm\grammarterm% \let\grammarterm\nocode% \let\omname\mname% @@ -157,6 +159,7 @@ \let\BreakableUnderscore\textunderscore% \edef\x{#1}% \let\tcode\otcode% +\let\exposid\oexposid% \let\grammarterm\gterm% \let\mname\omname% \let\Cpp\oCpp% @@ -515,7 +518,7 @@ \newcommand{\cvqual}[1]{\textit{#1}} \newcommand{\cv}{\ifmmode\mathit{cv}\else\cvqual{cv}\fi} \newcommand{\numconst}[1]{\textsl{#1}} -\newcommand{\logop}[1]{{\footnotesize #1}} +\newcommand{\logop}[1]{\textsc{#1}} %%-------------------------------------------------- %% Environments for code listings. diff --git a/source/memory.tex b/source/memory.tex index 576a28b9fc..9dc24f3078 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -70,75 +70,97 @@ namespace std { // \ref{pointer.traits}, pointer traits - template struct pointer_traits; - template struct pointer_traits; + template struct pointer_traits; // freestanding + template struct pointer_traits; // freestanding // \ref{pointer.conversion}, pointer conversion template - constexpr T* to_address(T* p) noexcept; + constexpr T* to_address(T* p) noexcept; // freestanding template - constexpr auto to_address(const Ptr& p) noexcept; + constexpr auto to_address(const Ptr& p) noexcept; // freestanding // \ref{ptr.align}, pointer alignment - void* align(size_t alignment, size_t size, void*& ptr, size_t& space); + void* align(size_t alignment, size_t size, void*& ptr, size_t& space); // freestanding template - [[nodiscard]] constexpr T* assume_aligned(T* ptr); + [[nodiscard]] constexpr T* assume_aligned(T* ptr); // freestanding + + // \ref{obj.lifetime}, explicit lifetime management + template + T* start_lifetime_as(void* p) noexcept; + template + const T* start_lifetime_as(const void* p) noexcept; + template + volatile T* start_lifetime_as(volatile void* p) noexcept; + template + const volatile T* start_lifetime_as(const volatile void* p) noexcept; + template + T* start_lifetime_as_array(void* p, size_t n) noexcept; + template + const T* start_lifetime_as_array(const void* p, size_t n) noexcept; + template + volatile T* start_lifetime_as_array(volatile void* p, size_t n) noexcept; + template + const volatile T* start_lifetime_as_array(const volatile void* p, size_t n) noexcept; // \ref{allocator.tag}, allocator argument tag - struct allocator_arg_t { explicit allocator_arg_t() = default; }; - inline constexpr allocator_arg_t allocator_arg{}; + struct allocator_arg_t { // freestanding + explicit allocator_arg_t() = default; // freestanding + }; + inline constexpr allocator_arg_t allocator_arg{}; // freestanding // \ref{allocator.uses}, \tcode{uses_allocator} - template struct uses_allocator; + template struct uses_allocator; // freestanding // \ref{allocator.uses.trait}, \tcode{uses_allocator} template - inline constexpr bool @\libglobal{uses_allocator_v}@ = uses_allocator::value; + inline constexpr bool @\libglobal{uses_allocator_v}@ = uses_allocator::value; // freestanding // \ref{allocator.uses.construction}, uses-allocator construction template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding Args&&... args) noexcept; template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding + piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept; template - constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; + constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; // freestanding template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding U&& u, V&& v) noexcept; template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding pair& pr) noexcept; template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding const pair& pr) noexcept; template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding pair&& pr) noexcept; template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding const pair&& pr) noexcept; template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding + U&& u) noexcept; template - constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); + constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); // freestanding template - constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, - Args&&... args); + constexpr T* uninitialized_construct_using_allocator(T* p, // freestanding + const Alloc& alloc, Args&&... args); // \ref{allocator.traits}, allocator traits - template struct allocator_traits; + template struct allocator_traits; // freestanding template - struct allocation_result { + struct allocation_result { // freestanding Pointer ptr; size_t count; }; template - [[nodiscard] constexpr allocation_result::pointer> - allocate_at_least(Allocator& a, size_t n); + [[nodiscard]] constexpr allocation_result::pointer> + allocate_at_least(Allocator& a, size_t n); // freestanding // \ref{default.allocator}, the default allocator template class allocator; @@ -147,9 +169,9 @@ // \ref{specialized.addressof}, addressof template - constexpr T* addressof(T& r) noexcept; + constexpr T* addressof(T& r) noexcept; // freestanding template - const T* addressof(const T&&) = delete; + const T* addressof(const T&&) = delete; // freestanding // \ref{specialized.algorithms}, specialized algorithms // \ref{special.mem.concepts}, special memory concepts @@ -165,208 +187,215 @@ concept @\exposconcept{nothrow-forward-range}@ = @\seebelow@; // \expos template - void uninitialized_default_construct(NoThrowForwardIterator first, + void uninitialized_default_construct(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last); template - void uninitialized_default_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void uninitialized_default_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, NoThrowForwardIterator last); template NoThrowForwardIterator - uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); + uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); // freestanding template NoThrowForwardIterator - uninitialized_default_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + uninitialized_default_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, 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); + 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); + 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); + I uninitialized_default_construct_n(I first, iter_difference_t n); // freestanding } template - void uninitialized_value_construct(NoThrowForwardIterator first, + void uninitialized_value_construct(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last); template - void uninitialized_value_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void uninitialized_value_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, NoThrowForwardIterator last); template NoThrowForwardIterator - uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); + uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); // freestanding template NoThrowForwardIterator - uninitialized_value_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + uninitialized_value_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, 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); + 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); + 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); + I uninitialized_value_construct_n(I first, iter_difference_t n); // freestanding } template - NoThrowForwardIterator uninitialized_copy(InputIterator first, InputIterator last, + NoThrowForwardIterator uninitialized_copy(InputIterator first, // freestanding + InputIterator last, NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, + NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, // freestanding NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} ForwardIterator first, Size n, NoThrowForwardIterator result); namespace ranges { template - using uninitialized_copy_result = in_out_result; + using uninitialized_copy_result = in_out_result; // freestanding 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 - uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); + 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> - uninitialized_copy(IR&& in_range, OR&& out_range); + uninitialized_copy(IR&& in_range, OR&& out_range); // freestanding template - using uninitialized_copy_n_result = in_out_result; + 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 - uninitialized_copy_n(I ifirst, iter_difference_t n, O ofirst, S olast); + uninitialized_copy_n(I ifirst, iter_difference_t n, // freestanding + O ofirst, S olast); } template - NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, + NoThrowForwardIterator uninitialized_move(InputIterator first, // freestanding + InputIterator last, NoThrowForwardIterator result); template - NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} ForwardIterator first, ForwardIterator last, NoThrowForwardIterator result); template pair - uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result); + uninitialized_move_n(InputIterator first, Size n, // freestanding + NoThrowForwardIterator result); template pair - uninitialized_move_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + uninitialized_move_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} ForwardIterator first, Size n, NoThrowForwardIterator result); namespace ranges { template - using uninitialized_move_result = in_out_result; + using uninitialized_move_result = in_out_result; // freestanding 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 - uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); + 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> - uninitialized_move(IR&& in_range, OR&& out_range); + uninitialized_move(IR&& in_range, OR&& out_range); // freestanding template - using uninitialized_move_n_result = in_out_result; + using uninitialized_move_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_rvalue_reference_t> uninitialized_move_n_result - uninitialized_move_n(I ifirst, iter_difference_t n, O ofirst, S olast); + uninitialized_move_n(I ifirst, iter_difference_t n, // freestanding + O ofirst, S olast); } template - void uninitialized_fill(NoThrowForwardIterator first, NoThrowForwardIterator last, - const T& x); + void uninitialized_fill(NoThrowForwardIterator first, // freestanding + NoThrowForwardIterator last, const T& x); template - void uninitialized_fill(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void uninitialized_fill(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, NoThrowForwardIterator last, const T& x); template NoThrowForwardIterator - uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); + uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); // freestanding template NoThrowForwardIterator - uninitialized_fill_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + uninitialized_fill_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, 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); + 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); + 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); + I uninitialized_fill_n(I first, iter_difference_t n, const T& x); // freestanding } // \ref{specialized.construct}, \tcode{construct_at} template - constexpr T* construct_at(T* location, Args&&... args); + constexpr T* construct_at(T* location, Args&&... args); // freestanding namespace ranges { template - constexpr T* construct_at(T* location, Args&&... args); + constexpr T* construct_at(T* location, Args&&... args); // freestanding } // \ref{specialized.destroy}, \tcode{destroy} template - constexpr void destroy_at(T* location); + constexpr void destroy_at(T* location); // freestanding template - constexpr void destroy(NoThrowForwardIterator first, NoThrowForwardIterator last); + constexpr void destroy(NoThrowForwardIterator first, // freestanding + NoThrowForwardIterator last); template - void destroy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + void destroy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, NoThrowForwardIterator last); template - constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, Size n); + constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, // freestanding + Size n); template - NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator first, Size n); namespace ranges { template<@\libconcept{destructible}@ T> - constexpr void destroy_at(T* location) noexcept; + constexpr void destroy_at(T* location) noexcept; // freestanding template<@\exposconcept{nothrow-input-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{destructible}@> - constexpr I destroy(I first, S last) noexcept; + constexpr I destroy(I first, S last) noexcept; // freestanding template<@\exposconcept{nothrow-input-range}@ R> requires @\libconcept{destructible}@> - constexpr borrowed_iterator_t destroy(R&& r) noexcept; + constexpr borrowed_iterator_t destroy(R&& r) noexcept; // freestanding template<@\exposconcept{nothrow-input-iterator}@ I> requires @\libconcept{destructible}@> - constexpr I destroy_n(I first, iter_difference_t n) noexcept; + constexpr I destroy_n(I first, iter_difference_t n) noexcept; // freestanding } // \ref{unique.ptr}, class template \tcode{unique_ptr} - template struct default_delete; - template struct default_delete; - template> class unique_ptr; - template class unique_ptr; + template struct default_delete; // freestanding + template struct default_delete; // freestanding + template> class unique_ptr; // freestanding + template class unique_ptr; // freestanding template constexpr unique_ptr make_unique(Args&&... args); // \tcode{T} is not array @@ -383,47 +412,48 @@ @\unspecnc@ make_unique_for_overwrite(Args&&...) = delete; // \tcode{T} is \tcode{U[N]} template - constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; + constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; // freestanding template - constexpr bool operator==(const unique_ptr& x, const unique_ptr& y); + constexpr bool operator==(const unique_ptr& x, // freestanding + const unique_ptr& y); template - bool operator<(const unique_ptr& x, const unique_ptr& y); + bool operator<(const unique_ptr& x, const unique_ptr& y); // freestanding template - bool operator>(const unique_ptr& x, const unique_ptr& y); + bool operator>(const unique_ptr& x, const unique_ptr& y); // freestanding template - bool operator<=(const unique_ptr& x, const unique_ptr& y); + bool operator<=(const unique_ptr& x, const unique_ptr& y); // freestanding template - bool operator>=(const unique_ptr& x, const unique_ptr& y); + bool operator>=(const unique_ptr& x, const unique_ptr& y); // freestanding template requires @\libconcept{three_way_comparable_with}@::pointer, typename unique_ptr::pointer> compare_three_way_result_t::pointer, typename unique_ptr::pointer> - operator<=>(const unique_ptr& x, const unique_ptr& y); + operator<=>(const unique_ptr& x, const unique_ptr& y); // freestanding template - constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; + constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; // freestanding template - constexpr bool operator<(const unique_ptr& x, nullptr_t); + constexpr bool operator<(const unique_ptr& x, nullptr_t); // freestanding template - constexpr bool operator<(nullptr_t, const unique_ptr& y); + constexpr bool operator<(nullptr_t, const unique_ptr& y); // freestanding template - constexpr bool operator>(const unique_ptr& x, nullptr_t); + constexpr bool operator>(const unique_ptr& x, nullptr_t); // freestanding template - constexpr bool operator>(nullptr_t, const unique_ptr& y); + constexpr bool operator>(nullptr_t, const unique_ptr& y); // freestanding template - constexpr bool operator<=(const unique_ptr& x, nullptr_t); + constexpr bool operator<=(const unique_ptr& x, nullptr_t); // freestanding template - constexpr bool operator<=(nullptr_t, const unique_ptr& y); + constexpr bool operator<=(nullptr_t, const unique_ptr& y); // freestanding template - constexpr bool operator>=(const unique_ptr& x, nullptr_t); + constexpr bool operator>=(const unique_ptr& x, nullptr_t); // freestanding template - constexpr bool operator>=(nullptr_t, const unique_ptr& y); + constexpr bool operator>=(nullptr_t, const unique_ptr& y); // freestanding template requires @\libconcept{three_way_comparable}@::pointer> constexpr compare_three_way_result_t::pointer> - operator<=>(const unique_ptr& x, nullptr_t); + operator<=>(const unique_ptr& x, nullptr_t); // freestanding template basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); @@ -525,12 +555,12 @@ template class enable_shared_from_this; // \ref{util.smartptr.hash}, hash support - template struct hash; - template struct hash>; + template struct hash; // freestanding + template struct hash>; // freestanding template struct hash>; // \ref{util.smartptr.atomic}, atomic smart pointers - template struct atomic; + template struct atomic; // freestanding template struct atomic>; template struct atomic>; @@ -799,6 +829,83 @@ \end{note} \end{itemdescr} +\rSec2[obj.lifetime]{Explicit lifetime management} + +\indexlibraryglobal{start_lifetime_as}% +\begin{itemdecl} +template + T* start_lifetime_as(void* p) noexcept; +template + const T* start_lifetime_as(const void* p) noexcept; +template + volatile T* start_lifetime_as(volatile void* p) noexcept; +template + const volatile T* start_lifetime_as(const volatile void* p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is an implicit-lifetime type\iref{basic.types.general}. + +\pnum +\expects +\range{p}{(char*)p + sizeof(T)} denotes a region of allocated storage +that is +a subset of the region of storage +reachable through\iref{basic.compound} \tcode{p} and +suitably aligned for the type \tcode{T}. + +\pnum +\effects +Implicitly creates objects\iref{intro.object} within the denoted region +consisting of an object \placeholder{a} of type \tcode{T} +whose address is \tcode{p}, and +objects nested within \placeholder{a}, +as follows: +The object representation of \placeholder{a} +is the contents of the storage prior to the call to \tcode{start_lifetime_as}. +The value of each created object \placeholder{o} +of trivially-copyable type \tcode{U} +is determined in the same manner as for a call +to \tcode{bit_cast(E)}\iref{bit.cast}, +where \tcode{E} is an lvalue of type \tcode{U} denoting \placeholder{o}, +except that the storage is not accessed. +The value of any other created object is unspecified. +\begin{note} +The unspecified value can be indeterminate. +\end{note} + +\pnum +\returns +% FIXME: We should introduce "a" outside of the \effects clause +A pointer to the \placeholder{a} defined in the \Fundescx{Effects} paragraph. +\end{itemdescr} + +\indexlibraryglobal{start_lifetime_as_array}% +\begin{itemdecl} +template + T* start_lifetime_as_array(void* p, size_t n) noexcept; +template + const T* start_lifetime_as_array(const void* p, size_t n) noexcept; +template + volatile T* start_lifetime_as_array(volatile void* p, size_t n) noexcept; +template + const volatile T* start_lifetime_as_array(const volatile void* p, size_t n) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{n > 0} is \tcode{true}. + +\pnum +\effects +Equivalent to: +\tcode{return *start_lifetime_as(p);} +where \tcode{U} is the type ``array of \tcode{n} \tcode{T}''. +\end{itemdescr} + \rSec2[allocator.tag]{Allocator argument tag} \indexlibraryglobal{allocator_arg_t}% @@ -3512,7 +3619,7 @@ \begin{itemdescr} \pnum \expects -\tcode{get() != 0}. +\tcode{get() != nullptr}. \pnum \returns @@ -3535,7 +3642,7 @@ \begin{itemdescr} \pnum \expects -\tcode{get() != 0}. +\tcode{get() != nullptr}. \pnum \returns @@ -3558,7 +3665,7 @@ \begin{itemdescr} \pnum \expects -\tcode{get() != 0 \&\& i >= 0}. +\tcode{get() != nullptr \&\& i >= 0}. If \tcode{T} is \tcode{U[N]}, \tcode{i < N}. \pnum @@ -3624,7 +3731,7 @@ \begin{itemdescr} \pnum \returns -\tcode{get() != 0}. +\tcode{get() != nullptr}. \end{itemdescr} \indexlibrarymember{owner_before}{shared_ptr}% @@ -3690,7 +3797,7 @@ \pnum \ensures -\tcode{r.get() != 0 \&\& r.use_count() == 1}, +\tcode{r.get() != nullptr \&\& r.use_count() == 1}, where \tcode{r} is the return value. \pnum @@ -3815,7 +3922,7 @@ \pnum \returns A \tcode{shared_ptr} to an object of type \tcode{T} -with an initial value \tcode{T(forward(args)...)}. +with an initial value \tcode{T(std::forward(args)...)}. \pnum \remarks @@ -5392,7 +5499,8 @@ \pnum A specialization of class template \tcode{pmr::polymorphic_allocator} meets -the \oldconcept{Allocator} requirements\iref{allocator.requirements.general}. +the \oldconcept{Allocator} requirements\iref{allocator.requirements.general} +if its template argument is a \cv-unqualified object type. Constructed with different memory resources, different instances of the same specialization of \tcode{pmr::polymorphic_allocator} can exhibit entirely different allocation behavior. @@ -5401,8 +5509,9 @@ even though they use the same static allocator type. \pnum -All specializations of class template \tcode{pmr::polymorphic_allocator} -meet the allocator completeness requirements\iref{allocator.requirements.completeness}. +A specialization of class template \tcode{pmr::polymorphic_allocator} +meets the allocator completeness requirements\iref{allocator.requirements.completeness} +if its template argument is a \cv-unqualified object type. \indexlibraryglobal{polymorphic_allocator}% \indexlibrarymember{value_type}{polymorphic_allocator}% @@ -5442,6 +5551,12 @@ polymorphic_allocator select_on_container_copy_construction() const; memory_resource* resource() const; + + // friends + friend bool operator==(const polymorphic_allocator& a, + const polymorphic_allocator& b) noexcept { + return *a.resource() == *b.resource(); + } }; } \end{codeblock} @@ -6311,7 +6426,7 @@ \indexheader{scoped_allocator}% \begin{codeblock} namespace std { - // class template \tcode{scoped allocator adaptor} + // class template \tcode{scoped_allocator_adaptor} template class scoped_allocator_adaptor; diff --git a/source/meta.tex b/source/meta.tex index 6c6d7914fd..11f69c16e7 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -154,6 +154,7 @@ \indexheader{type_traits}% % FIXME: Many index entries missing. \begin{codeblock} +// all freestanding namespace std { // \ref{meta.help}, helper class template struct integral_constant; @@ -1341,7 +1342,7 @@ \indexlibraryglobal{rank}% \tcode{template\br struct rank;} & - If \tcode{T} names an array type, an integer value representing + If \tcode{T} is an array type, an integer value representing the number of dimensions of \tcode{T}; otherwise, 0. \\ \rowsep \indexlibraryglobal{extent}% @@ -1419,7 +1420,7 @@ 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} @@ -1587,9 +1588,8 @@ \indexlibraryglobal{remove_const}% \tcode{template\br struct remove_const;} & - The member typedef \tcode{type} names - the same type as \tcode{T} - except that any top-level const-qualifier has been removed. + The member typedef \tcode{type} denotes the type formed + by removing any top-level const-qualifier from \tcode{T}. \begin{tailexample} \tcode{remove_const_t} evaluates to \tcode{volatile int}, whereas \tcode{remove_const_t} evaluates to @@ -1600,9 +1600,8 @@ \indexlibraryglobal{remove_volatile}% \tcode{template\br struct remove_volatile;} & - The member typedef \tcode{type} names - the same type as \tcode{T} - except that any top-level volatile-qualifier has been removed. + The member typedef \tcode{type} denotes the type formed + by removing any top-level volatile-qualifier from \tcode{T}. \begin{tailexample} \tcode{remove_volatile_t} evaluates to \tcode{const int}, @@ -1613,8 +1612,8 @@ \indexlibraryglobal{remove_cv}% \tcode{template\br struct remove_cv;} & - The member typedef \tcode{type} shall be the same as \tcode{T} - except that any top-level cv-qualifier has been removed. + The member typedef \tcode{type} denotes the type formed + by removing any top-level cv-qualifiers from \tcode{T}. \begin{tailexample} \tcode{remove_cv_t} evaluates to \tcode{int}, whereas \tcode{remove_cv_t} @@ -1626,23 +1625,20 @@ \tcode{template\br struct add_const;} & If \tcode{T} is a reference, function, or top-level const-qualified - type, then \tcode{type} names - the same type as \tcode{T}, otherwise + type, then \tcode{type} denotes \tcode{T}, otherwise \tcode{T const}. \\ \rowsep \indexlibraryglobal{add_volatile}% \tcode{template\br struct add_volatile;} & If \tcode{T} is a reference, function, or top-level volatile-qualified - type, then \tcode{type} names - the same type as \tcode{T}, otherwise + type, then \tcode{type} denotes \tcode{T}, otherwise \tcode{T volatile}. \\ \rowsep \indexlibraryglobal{add_cv}% \tcode{template\br struct add_cv;} & - The member typedef \tcode{type} names - the same type as + The member typedef \tcode{type} denotes \tcode{add_const_t>}. \\ \end{libreqtab2a} @@ -1661,15 +1657,15 @@ \tcode{template\br struct remove_reference;} & If \tcode{T} has type ``reference to \tcode{T1}'' then the - member typedef \tcode{type} names \tcode{T1}; - otherwise, \tcode{type} names \tcode{T}.\\ \rowsep + member typedef \tcode{type} denotes \tcode{T1}; + otherwise, \tcode{type} denotes \tcode{T}.\\ \rowsep \indexlibraryglobal{add_lvalue_reference}% \tcode{template\br struct add_lvalue_reference;} & - If \tcode{T} names a referenceable type\iref{defns.referenceable} then - the member typedef \tcode{type} names \tcode{T\&}; - otherwise, \tcode{type} names \tcode{T}. + If \tcode{T} is a referenceable type\iref{defns.referenceable} then + the member typedef \tcode{type} denotes \tcode{T\&}; + otherwise, \tcode{type} denotes \tcode{T}. \begin{tailnote} This rule reflects the semantics of reference collapsing\iref{dcl.ref}. \end{tailnote} @@ -1678,13 +1674,13 @@ \indexlibraryglobal{add_rvalue_reference}% \tcode{template}\br \tcode{struct add_rvalue_reference;} & - If \tcode{T} names a referenceable type then - the member typedef \tcode{type} names \tcode{T\&\&}; - otherwise, \tcode{type} names \tcode{T}. + If \tcode{T} is a referenceable type then + the member typedef \tcode{type} denotes \tcode{T\&\&}; + otherwise, \tcode{type} denotes \tcode{T}. \begin{tailnote} This rule reflects the semantics of reference collapsing\iref{dcl.ref}. - For example, when a type \tcode{T} names a type \tcode{T1\&}, the type - \tcode{add_rvalue_reference_t} is not an rvalue reference. + For example, when a type \tcode{T} is a reference type \tcode{T1\&}, + the type \tcode{add_rvalue_reference_t} is not an rvalue reference. \end{tailnote} \\ \end{libreqtab2a} @@ -1702,13 +1698,13 @@ \indexlibraryglobal{make_signed}% \tcode{template}\br \tcode{struct make_signed;} & - If \tcode{T} names a (possibly cv-qualified) signed integer + If \tcode{T} is a (possibly cv-qualified) signed integer type\iref{basic.fundamental} then the member typedef - \tcode{type} names the type \tcode{T}; otherwise, - if \tcode{T} names a (possibly cv-qualified) unsigned integer - type then \tcode{type} names the corresponding + \tcode{type} denotes \tcode{T}; otherwise, + if \tcode{T} is a (possibly cv-qualified) unsigned integer + type then \tcode{type} denotes the corresponding signed integer type, with the same cv-qualifiers as \tcode{T}; - otherwise, \tcode{type} names the signed integer type with smallest + otherwise, \tcode{type} denotes the signed integer type with smallest rank\iref{conv.rank} for which \tcode{sizeof(T) == sizeof(type)}, with the same cv-qualifiers as \tcode{T}.\br @@ -1718,13 +1714,13 @@ \indexlibraryglobal{make_unsigned}% \tcode{template}\br \tcode{struct make_unsigned;} & - If \tcode{T} names a (possibly cv-qualified) unsigned integer + If \tcode{T} is a (possibly cv-qualified) unsigned integer type\iref{basic.fundamental} then the member typedef - \tcode{type} names the type \tcode{T}; otherwise, - if \tcode{T} names a (possibly cv-qualified) signed integer - type then \tcode{type} names the corresponding + \tcode{type} denotes \tcode{T}; otherwise, + if \tcode{T} is a (possibly cv-qualified) signed integer + type then \tcode{type} denotes the corresponding unsigned integer type, with the same cv-qualifiers as \tcode{T}; - otherwise, \tcode{type} names the unsigned integer type with smallest + otherwise, \tcode{type} denotes the unsigned integer type with smallest rank\iref{conv.rank} for which \tcode{sizeof(T) == sizeof(type)}, with the same cv-qualifiers as \tcode{T}.\br @@ -1745,9 +1741,9 @@ \indexlibraryglobal{remove_extent}% \tcode{template\br struct remove_extent;} & - If \tcode{T} names a type ``array of \tcode{U}'', - the member typedef \tcode{type} shall - be \tcode{U}, otherwise \tcode{T}. + If \tcode{T} is a type ``array of \tcode{U}'', + the member typedef \tcode{type} denotes \tcode{U}, + otherwise \tcode{T}. \begin{tailnote} For multidimensional arrays, only the first array dimension is removed. For a type ``array of \tcode{const U}'', the resulting type is @@ -1759,7 +1755,7 @@ \tcode{template\br struct remove_all_extents;} & If \tcode{T} is ``multi-dimensional array of \tcode{U}'', the resulting member - typedef \tcode{type} is \tcode{U}, otherwise \tcode{T}. \\ + typedef \tcode{type} denotes \tcode{U}, otherwise \tcode{T}. \\ \end{libreqtab2a} \pnum @@ -1799,16 +1795,16 @@ struct remove_pointer;} & If \tcode{T} has type ``(possibly cv-qualified) pointer to \tcode{T1}'' then the member typedef \tcode{type} - names \tcode{T1}; otherwise, it names \tcode{T}.\\ \rowsep + denotes \tcode{T1}; otherwise, it denotes \tcode{T}.\\ \rowsep \indexlibraryglobal{add_pointer}% \tcode{template\br struct add_pointer;} & - If \tcode{T} names a referenceable type\iref{defns.referenceable} or a + If \tcode{T} is a referenceable type\iref{defns.referenceable} or a \cv{}~\keyword{void} type then - the member typedef \tcode{type} names the same type as + the member typedef \tcode{type} denotes \tcode{remove_reference_t*}; - otherwise, \tcode{type} names \tcode{T}. \\ + otherwise, \tcode{type} denotes \tcode{T}. \\ \end{libreqtab2a} \rSec3[meta.trans.other]{Other transformations} @@ -1826,12 +1822,12 @@ \tcode{template\br struct type_identity;} & - The member typedef \tcode{type} names the type \tcode{T}. \\ \rowsep + The member typedef \tcode{type} denotes \tcode{T}. \\ \rowsep \indexlibraryglobal{remove_cvref}% \tcode{template\br struct remove_cvref;} & - The member typedef \tcode{type} names the same type as + The member typedef \tcode{type} denotes \tcode{remove_cv_t>}. \\ \rowsep @@ -1839,10 +1835,10 @@ \tcode{template\br struct decay;} & Let \tcode{U} be \tcode{remove_reference_t}. If \tcode{is_array_v} is - \tcode{true}, the member typedef \tcode{type} equals + \tcode{true}, the member typedef \tcode{type} denotes \tcode{remove_extent_t*}. If \tcode{is_function_v} is \tcode{true}, - the member typedef \tcode{type} equals \tcode{add_pointer_t}. Otherwise - the member typedef \tcode{type} equals \tcode{remove_cv_t}. + the member typedef \tcode{type} denotes \tcode{add_pointer_t}. Otherwise + the member typedef \tcode{type} denotes \tcode{remove_cv_t}. \begin{tailnote} This behavior is similar to the lvalue-to-rvalue\iref{conv.lval}, array-to-pointer\iref{conv.array}, and function-to-pointer\iref{conv.func} @@ -1856,15 +1852,15 @@ \tcode{template} \tcode{struct enable_if;} & If \tcode{B} is \tcode{true}, the member typedef \tcode{type} - shall equal \tcode{T}; otherwise, there shall be no member + denotes \tcode{T}; otherwise, there shall be no member \tcode{type}. \\ \rowsep \tcode{template}\br \tcode{struct conditional;} & - If \tcode{B} is \tcode{true}, the member typedef \tcode{type} shall equal \tcode{T}. - If \tcode{B} is \tcode{false}, the member typedef \tcode{type} shall equal \tcode{F}. \\ \rowsep + 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;} & @@ -1895,7 +1891,7 @@ \tcode{template}\br \tcode{struct underlying_type;} & - If \tcode{T} is an enumeration type, the member typedef \tcode{type} names + 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 @@ -1906,7 +1902,7 @@ & If the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand}, - the member typedef \tcode{type} names the type + the member typedef \tcode{type} denotes the type \tcode{decltype(\placeholdernc{INVOKE}(declval(), declval()...))}; otherwise, there shall be no member \tcode{type}. Access checking is performed as if in a context unrelated to \tcode{Fn} and @@ -1928,8 +1924,9 @@ & If \tcode{T} is a specialization \tcode{reference_wrapper} for some type \tcode{X}, - the member typedef \tcode{type} of \tcode{unwrap_reference} is \tcode{X\&}, - otherwise it is \tcode{T}. \\ \rowsep + the member typedef \tcode{type} of \tcode{unwrap_reference} + denotes \tcode{X\&}, + otherwise \tcode{type} denotes \tcode{T}. \\ \rowsep \indexlibraryglobal{unwrap_ref_decay}% \tcode{template} \tcode{unwrap_ref_decay;} @@ -2413,6 +2410,7 @@ \indexheader{ratio}% \begin{codeblockdigitsep} +// all freestanding namespace std { // \ref{ratio.ratio}, class template \tcode{ratio} template class ratio; @@ -2507,6 +2505,10 @@ \rSec2[ratio.arithmetic]{Arithmetic on \tcode{ratio}{s}} \pnum +\indexlibraryglobal{ratio_add}% +\indexlibraryglobal{ratio_subtract}% +\indexlibraryglobal{ratio_multiply}% +\indexlibraryglobal{ratio_divide}% Each of the alias templates \tcode{ratio_add}, \tcode{ratio_subtract}, \tcode{ratio_multiply}, and \tcode{ratio_divide} denotes the result of an arithmetic computation on two \tcode{ratio}{s} \tcode{R1} and \tcode{R2}. With \tcode{X} and \tcode{Y} computed (in the diff --git a/source/modules.tex b/source/modules.tex index cfd4928bb7..3701762ced 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -148,10 +148,8 @@ it is attached to the module to which the friend is attached\iref{basic.link}. \item Otherwise, if the declaration \begin{itemize} -\item is a replaceable global allocation or deallocation -function\iref{new.delete.single,new.delete.array}, or -\item is a \grammarterm{namespace-definition} with external linkage, or -\item appears within a \grammarterm{linkage-specification}, +\item is a \grammarterm{namespace-definition} with external linkage or +\item appears within a \grammarterm{linkage-specification}\iref{dcl.link} \end{itemize} it is attached to the global module. @@ -608,11 +606,19 @@ \item $S$ contains a dependent call \tcode{E}\iref{temp.dep} -and $D$ is found by name lookup for the dependent name -in an expression synthesized from \tcode{E} +and $D$ is found by any name lookup performed +for an expression synthesized from \tcode{E} by replacing each type-dependent argument or operand with a value of a placeholder type with no associated namespaces or entities, or +\begin{note} +This includes the lookup for \tcode{\keyword{operator}==} performed +when considering rewriting an \tcode{!=} expression, +the lookup for \tcode{\keyword{operator}<=>} +performed when considering rewriting a relational comparison, and +the lookup for \tcode{\keyword{operator}!=} +when considering whether an \tcode{\keyword{operator}==} is a rewrite target. +\end{note} \item $S$ contains an expression that @@ -797,7 +803,7 @@ \begin{itemize} \item the point by which the definition of -an exported inline function +an inline function or variable is required\iref{dcl.inline}, \item @@ -827,12 +833,11 @@ export module A; export inline void fn_e(); // error: exported inline function \tcode{fn_e} not defined // before private module fragment -inline void fn_m(); // OK, module-linkage inline function +inline void fn_m(); // error: non-exported inline function \tcode{fn_m} not defined static void fn_s(); export struct X; export void g(X *x) { fn_s(); // OK, call to static function in same translation unit - fn_m(); // OK, call to module-linkage inline function } export X *factory(); // OK diff --git a/source/numerics.tex b/source/numerics.tex index 811f7d9d90..514319824d 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -190,13 +190,11 @@ and numerous functions for representing and manipulating complex numbers. \pnum -The effect of instantiating the template -\tcode{complex} -for any type other than \tcode{float}, \tcode{double}, or \tcode{long double} is unspecified. -The specializations -\tcode{complex}, -\tcode{complex}, and -\tcode{complex} are literal types\iref{term.literal.type}. +The effect of instantiating the template \tcode{complex} for any type +that is not a cv-unqualified floating-point type\iref{basic.fundamental} +is unspecified. +Specializations of \tcode{complex} for cv-unqualified floating-point types +are trivially-copyable literal types\iref{term.literal.type}. \pnum If the result of a function is not mathematically defined or not in @@ -225,11 +223,6 @@ // \ref{complex}, class template \tcode{complex} template class complex; - // \ref{complex.special}, specializations - template<> class complex; - template<> class complex; - template<> class complex; - // \ref{complex.ops}, operators template constexpr complex operator+(const complex&, const complex&); template constexpr complex operator+(const complex&, const T&); @@ -321,8 +314,8 @@ using value_type = T; constexpr complex(const T& re = T(), const T& im = T()); - constexpr complex(const complex&); - template constexpr complex(const complex&); + constexpr complex(const complex&) = default; + template constexpr explicit(@\seebelow@) complex(const complex&); constexpr T real() const; constexpr void real(T); @@ -356,101 +349,11 @@ of a complex number. -\rSec2[complex.special]{Specializations} - -\begin{codeblock} -namespace std { - template<> class complex { - public: - using value_type = float; - - constexpr complex(float re = 0.0f, float im = 0.0f); - constexpr complex(const complex&) = default; - constexpr explicit complex(const complex&); - constexpr explicit complex(const complex&); - - constexpr float real() const; - constexpr void real(float); - constexpr float imag() const; - constexpr void imag(float); - - constexpr complex& operator= (float); - constexpr complex& operator+=(float); - constexpr complex& operator-=(float); - constexpr complex& operator*=(float); - constexpr complex& operator/=(float); - - constexpr complex& operator=(const complex&); - template constexpr complex& operator= (const complex&); - template constexpr complex& operator+=(const complex&); - template constexpr complex& operator-=(const complex&); - template constexpr complex& operator*=(const complex&); - template constexpr complex& operator/=(const complex&); - }; - - template<> class complex { - public: - using value_type = double; - - constexpr complex(double re = 0.0, double im = 0.0); - constexpr complex(const complex&); - constexpr complex(const complex&) = default; - constexpr explicit complex(const complex&); - - constexpr double real() const; - constexpr void real(double); - constexpr double imag() const; - constexpr void imag(double); - - constexpr complex& operator= (double); - constexpr complex& operator+=(double); - constexpr complex& operator-=(double); - constexpr complex& operator*=(double); - constexpr complex& operator/=(double); - - constexpr complex& operator=(const complex&); - template constexpr complex& operator= (const complex&); - template constexpr complex& operator+=(const complex&); - template constexpr complex& operator-=(const complex&); - template constexpr complex& operator*=(const complex&); - template constexpr complex& operator/=(const complex&); - }; - - template<> class complex { - public: - using value_type = long double; - - constexpr complex(long double re = 0.0L, long double im = 0.0L); - constexpr complex(const complex&); - constexpr complex(const complex&); - constexpr complex(const complex&) = default; - - constexpr long double real() const; - constexpr void real(long double); - constexpr long double imag() const; - constexpr void imag(long double); - - constexpr complex& operator= (long double); - constexpr complex& operator+=(long double); - constexpr complex& operator-=(long double); - constexpr complex& operator*=(long double); - constexpr complex& operator/=(long double); - - constexpr complex& operator=(const complex&); - template constexpr complex& operator= (const complex&); - template constexpr complex& operator+=(const complex&); - template constexpr complex& operator-=(const complex&); - template constexpr complex& operator*=(const complex&); - template constexpr complex& operator/=(const complex&); - }; -} -\end{codeblock} - \rSec2[complex.members]{Member functions} \indexlibraryctor{complex}% \begin{itemdecl} -template constexpr complex(const T& re = T(), const T& im = T()); +constexpr complex(const T& re = T(), const T& im = T()); \end{itemdecl} \begin{itemdescr} @@ -459,6 +362,24 @@ \tcode{real() == re \&\& imag() == im} is \tcode{true}. \end{itemdescr} +\indexlibraryctor{complex}% +\begin{itemdecl} +template constexpr explicit(@\seebelow@) complex(const complex& other); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the real part with \tcode{other.real()} and +the imaginary part with \tcode{other.imag()}. + +\pnum +\remarks +The expression inside \tcode{explicit} evaluates to \tcode{false} +if and only if the floating-point conversion rank of \tcode{T} +is greater than or equal to the floating-point conversion rank of \tcode{X}. +\end{itemdescr} + \indexlibrarymember{real}{complex}% \begin{itemdecl} constexpr T real() const; @@ -807,7 +728,7 @@ s.flags(o.flags()); s.imbue(o.getloc()); s.precision(o.precision()); -s << '(' << x.real() << "," << x.imag() << ')'; +s << '(' << x.real() << ',' << x.imag() << ')'; return o << s.str(); \end{codeblock} @@ -1203,28 +1124,22 @@ \indextext{overloads!floating-point}% The additional overloads shall be sufficient to ensure: \begin{itemize} - \item If the argument has type \tcode{long double}, then it is effectively - cast to \tcode{complex}. - \item Otherwise, if the argument has type \tcode{double} or an integer type, - then it is effectively cast to \tcode{complex<\brk{}double>}. - \item Otherwise, if the argument has type \tcode{float}, then it is - effectively cast to \tcode{complex}. +\item +If the argument has a floating-point type \tcode{T}, +then it is effectively cast to \tcode{complex}. +\item +Otherwise, if the argument has integer type, +then it is effectively cast to \tcode{complex}. \end{itemize} \pnum \indexlibraryglobal{pow}% -Function template \tcode{pow} shall have additional overloads sufficient to -ensure, for a call with at least one argument of type \tcode{complex}: -\begin{itemize} - \item If either argument has type \tcode{complex} or type \tcode{long - double}, then both arguments are effectively cast to - \tcode{complex}. - \item Otherwise, if either argument has type \tcode{complex}, \tcode{double}, - or an integer type, then both arguments are effectively cast to - \tcode{complex}. - \item Otherwise, if either argument has type \tcode{complex} or \tcode{float}, - then both arguments are effectively cast to \tcode{complex}. -\end{itemize} +Function template \tcode{pow} has additional 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, +then the program is ill-formed. \rSec2[complex.literals]{Suffixes for complex number literals} @@ -1386,7 +1301,7 @@ \indextext{random number generation!synopsis|(} \begin{codeblock} -#include +#include // see \ref{initializer.list.syn} namespace std { // \ref{rand.req.urng}, uniform random bit generator requirements @@ -2440,7 +2355,7 @@ \tcode{os << d} or of any \keyword{const} member function of \tcode{D} -between any of the invocations \tcode{d(g)}. +between any of the invocations of \tcode{d(g)}. \pnum If a textual representation is written using \tcode{os << x} @@ -3178,7 +3093,7 @@ void discard(unsigned long long z); // property functions - const Engine& base() const noexcept { return e; }; + const Engine& base() const noexcept { return e; } // inserters and extractors template @@ -3217,7 +3132,7 @@ sets \tcode{n} to $0$. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% independent_bits_engine engine adaptor: +% independent_bits_engine engine adaptor:\exposid{ \rSec3[rand.adapt.ibits]{Class template \tcode{independent_bits_engine}}% \indexlibraryglobal{independent_bits_engine}% @@ -3326,7 +3241,7 @@ void discard(unsigned long long z); // property functions - const Engine& base() const noexcept { return e; }; + const Engine& base() const noexcept { return e; } // inserters and extractors template @@ -3428,7 +3343,7 @@ void discard(unsigned long long z); // property functions - const Engine& base() const noexcept { return e; }; + const Engine& base() const noexcept { return e; } // inserters and extractors template @@ -6568,7 +6483,7 @@ \rSec2[valarray.syn]{Header \tcode{} synopsis} \indexheader{valarray}% \begin{codeblock} -#include +#include // see \ref{initializer.list.syn} namespace std { template class valarray; // An array of type \tcode{T} @@ -7639,7 +7554,7 @@ \begin{example} If the argument has the value $-2$, the first two elements of the result will be value-initialized\iref{dcl.init}; the third element of the result will be assigned the value -of the first element of the argument; etc. +of the first element of \tcode{*this}; etc. \end{example} \end{itemdescr} @@ -7979,6 +7894,7 @@ public: slice(); slice(size_t, size_t, size_t); + slice(const slice&); size_t start() const; size_t size() const; @@ -8013,7 +7929,6 @@ \begin{itemdecl} slice(); slice(size_t start, size_t length, size_t stride); -slice(const slice&); \end{itemdecl} \begin{itemdescr} @@ -8314,7 +8229,6 @@ gslice(); gslice(size_t start, const valarray& lengths, const valarray& strides); -gslice(const gslice&); \end{itemdecl} \begin{itemdescr} @@ -8517,7 +8431,7 @@ \indexlibrarymember{operator[]}{mask_array}% \begin{itemdecl} -mask_array valarray::operator[](const valarray&). +mask_array valarray::operator[](const valarray&); \end{itemdecl} \pnum @@ -8634,7 +8548,7 @@ \indexlibrarymember{operator[]}{indirect_array}% \begin{itemdecl} -indirect_array valarray::operator[](const valarray&). +indirect_array valarray::operator[](const valarray&); \end{itemdecl} \pnum @@ -9028,171 +8942,115 @@ #define math_errhandling @\seebelow@ namespace std { - float acos(float x); // see \ref{library.c} - double acos(double x); - long double acos(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ acos(@\placeholder{floating-point-type}@ x); float acosf(float x); long double acosl(long double x); - float asin(float x); // see \ref{library.c} - double asin(double x); - long double asin(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ asin(@\placeholder{floating-point-type}@ x); float asinf(float x); long double asinl(long double x); - float atan(float x); // see \ref{library.c} - double atan(double x); - long double atan(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ atan(@\placeholder{floating-point-type}@ x); float atanf(float x); long double atanl(long double x); - float atan2(float y, float x); // see \ref{library.c} - double atan2(double y, double x); - long double atan2(long double y, long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ atan2(@\placeholder{floating-point-type}@ y, @\placeholder{floating-point-type}@ x); float atan2f(float y, float x); long double atan2l(long double y, long double x); - float cos(float x); // see \ref{library.c} - double cos(double x); - long double cos(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ cos(@\placeholder{floating-point-type}@ x); float cosf(float x); long double cosl(long double x); - float sin(float x); // see \ref{library.c} - double sin(double x); - long double sin(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ sin(@\placeholder{floating-point-type}@ x); float sinf(float x); long double sinl(long double x); - float tan(float x); // see \ref{library.c} - double tan(double x); - long double tan(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ tan(@\placeholder{floating-point-type}@ x); float tanf(float x); long double tanl(long double x); - float acosh(float x); // see \ref{library.c} - double acosh(double x); - long double acosh(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ acosh(@\placeholder{floating-point-type}@ x); float acoshf(float x); long double acoshl(long double x); - float asinh(float x); // see \ref{library.c} - double asinh(double x); - long double asinh(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ asinh(@\placeholder{floating-point-type}@ x); float asinhf(float x); long double asinhl(long double x); - float atanh(float x); // see \ref{library.c} - double atanh(double x); - long double atanh(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ atanh(@\placeholder{floating-point-type}@ x); float atanhf(float x); long double atanhl(long double x); - float cosh(float x); // see \ref{library.c} - double cosh(double x); - long double cosh(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ cosh(@\placeholder{floating-point-type}@ x); float coshf(float x); long double coshl(long double x); - float sinh(float x); // see \ref{library.c} - double sinh(double x); - long double sinh(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ sinh(@\placeholder{floating-point-type}@ x); float sinhf(float x); long double sinhl(long double x); - float tanh(float x); // see \ref{library.c} - double tanh(double x); - long double tanh(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ tanh(@\placeholder{floating-point-type}@ x); float tanhf(float x); long double tanhl(long double x); - float exp(float x); // see \ref{library.c} - double exp(double x); - long double exp(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ exp(@\placeholder{floating-point-type}@ x); float expf(float x); long double expl(long double x); - float exp2(float x); // see \ref{library.c} - double exp2(double x); - long double exp2(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ exp2(@\placeholder{floating-point-type}@ x); float exp2f(float x); long double exp2l(long double x); - float expm1(float x); // see \ref{library.c} - double expm1(double x); - long double expm1(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ expm1(@\placeholder{floating-point-type}@ x); float expm1f(float x); long double expm1l(long double x); - constexpr float frexp(float value, int* exp); // see \ref{library.c} - constexpr double frexp(double value, int* exp); - constexpr long double frexp(long double value, int* exp); // see \ref{library.c} + 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 int ilogb(float x); // see \ref{library.c} - constexpr int ilogb(double x); - constexpr int ilogb(long double x); // see \ref{library.c} + constexpr int ilogb(@\placeholder{floating-point-type}@ x); constexpr int ilogbf(float x); constexpr int ilogbl(long double x); - constexpr float ldexp(float x, int exp); // see \ref{library.c} - constexpr double ldexp(double x, int exp); - constexpr long double ldexp(long double x, int exp); // see \ref{library.c} + 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); - float log(float x); // see \ref{library.c} - double log(double x); - long double log(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ log(@\placeholder{floating-point-type}@ x); float logf(float x); long double logl(long double x); - float log10(float x); // see \ref{library.c} - double log10(double x); - long double log10(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ log10(@\placeholder{floating-point-type}@ x); float log10f(float x); long double log10l(long double x); - float log1p(float x); // see \ref{library.c} - double log1p(double x); - long double log1p(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ log1p(@\placeholder{floating-point-type}@ x); float log1pf(float x); long double log1pl(long double x); - float log2(float x); // see \ref{library.c} - double log2(double x); - long double log2(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ log2(@\placeholder{floating-point-type}@ x); float log2f(float x); long double log2l(long double x); - constexpr float logb(float x); // see \ref{library.c} - constexpr double logb(double x); - constexpr long double logb(long double x); // see \ref{library.c} + constexpr @\placeholder{floating-point-type}@ logb(@\placeholder{floating-point-type}@ x); constexpr float logbf(float x); constexpr long double logbl(long double x); - constexpr float modf(float value, float* iptr); // see \ref{library.c} - constexpr double modf(double value, double* iptr); - constexpr long double modf(long double value, long double* iptr); // see \ref{library.c} + 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 float scalbn(float x, int n); // see \ref{library.c} - constexpr double scalbn(double x, int n); - constexpr long double scalbn(long double x, int n); // see \ref{library.c} + 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 float scalbln(float x, long int n); // see \ref{library.c} - constexpr double scalbln(double x, long int n); - constexpr long double scalbln(long double x, long int n); // see \ref{library.c} + 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); - float cbrt(float x); // see \ref{library.c} - double cbrt(double x); - long double cbrt(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ cbrt(@\placeholder{floating-point-type}@ x); float cbrtf(float x); long double cbrtl(long double x); @@ -9200,144 +9058,97 @@ constexpr int abs(int j); constexpr long int abs(long int j); constexpr long long int abs(long long int j); - constexpr float abs(float j); - constexpr double abs(double j); - constexpr long double abs(long double j); + constexpr @\placeholder{floating-point-type}@ abs(@\placeholder{floating-point-type}@ j); - constexpr float fabs(float x); // see \ref{library.c} - constexpr double fabs(double x); - constexpr long double fabs(long double x); // see \ref{library.c} + constexpr @\placeholder{floating-point-type}@ fabs(@\placeholder{floating-point-type}@ x); constexpr float fabsf(float x); constexpr long double fabsl(long double x); - float hypot(float x, float y); // see \ref{library.c} - double hypot(double x, double y); - long double hypot(long double x, long double y); // see \ref{library.c} + @\placeholder{floating-point-type}@ hypot(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); float hypotf(float x, float y); long double hypotl(long double x, long double y); // \ref{c.math.hypot3}, three-dimensional hypotenuse - float hypot(float x, float y, float z); - double hypot(double x, double y, double z); - long double hypot(long double x, long double y, long double z); + @\placeholder{floating-point-type}@ hypot(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y, + @\placeholder{floating-point-type}@ z); - float pow(float x, float y); // see \ref{library.c} - double pow(double x, double y); - long double pow(long double x, long double y); // see \ref{library.c} + @\placeholder{floating-point-type}@ pow(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); float powf(float x, float y); long double powl(long double x, long double y); - float sqrt(float x); // see \ref{library.c} - double sqrt(double x); - long double sqrt(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ sqrt(@\placeholder{floating-point-type}@ x); float sqrtf(float x); long double sqrtl(long double x); - float erf(float x); // see \ref{library.c} - double erf(double x); - long double erf(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ erf(@\placeholder{floating-point-type}@ x); float erff(float x); long double erfl(long double x); - float erfc(float x); // see \ref{library.c} - double erfc(double x); - long double erfc(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ erfc(@\placeholder{floating-point-type}@ x); float erfcf(float x); long double erfcl(long double x); - float lgamma(float x); // see \ref{library.c} - double lgamma(double x); - long double lgamma(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ lgamma(@\placeholder{floating-point-type}@ x); float lgammaf(float x); long double lgammal(long double x); - float tgamma(float x); // see \ref{library.c} - double tgamma(double x); - long double tgamma(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ tgamma(@\placeholder{floating-point-type}@ x); float tgammaf(float x); long double tgammal(long double x); - constexpr float ceil(float x); // see \ref{library.c} - constexpr double ceil(double x); - constexpr long double ceil(long double x); // see \ref{library.c} + constexpr @\placeholder{floating-point-type}@ ceil(@\placeholder{floating-point-type}@ x); constexpr float ceilf(float x); constexpr long double ceill(long double x); - constexpr float floor(float x); // see \ref{library.c} - constexpr double floor(double x); - constexpr long double floor(long double x); // see \ref{library.c} + constexpr @\placeholder{floating-point-type}@ floor(@\placeholder{floating-point-type}@ x); constexpr float floorf(float x); constexpr long double floorl(long double x); - float nearbyint(float x); // see \ref{library.c} - double nearbyint(double x); - long double nearbyint(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ nearbyint(@\placeholder{floating-point-type}@ x); float nearbyintf(float x); long double nearbyintl(long double x); - float rint(float x); // see \ref{library.c} - double rint(double x); - long double rint(long double x); // see \ref{library.c} + @\placeholder{floating-point-type}@ rint(@\placeholder{floating-point-type}@ x); float rintf(float x); long double rintl(long double x); - long int lrint(float x); // see \ref{library.c} - long int lrint(double x); - long int lrint(long double x); // see \ref{library.c} + long int lrint(@\placeholder{floating-point-type}@ x); long int lrintf(float x); long int lrintl(long double x); - long long int llrint(float x); // see \ref{library.c} - long long int llrint(double x); - long long int llrint(long double x); // see \ref{library.c} + long long int llrint(@\placeholder{floating-point-type}@ x); long long int llrintf(float x); long long int llrintl(long double x); - constexpr float round(float x); // see \ref{library.c} - constexpr double round(double x); - constexpr long double round(long double x); // see \ref{library.c} + constexpr @\placeholder{floating-point-type}@ round(@\placeholder{floating-point-type}@ x); constexpr float roundf(float x); constexpr long double roundl(long double x); - constexpr long int lround(float x); // see \ref{library.c} - constexpr long int lround(double x); - constexpr long int lround(long double x); // see \ref{library.c} + constexpr long int lround(@\placeholder{floating-point-type}@ x); constexpr long int lroundf(float x); constexpr long int lroundl(long double x); - constexpr long long int llround(float x); // see \ref{library.c} - constexpr long long int llround(double x); - constexpr long long int llround(long double x); // see \ref{library.c} + constexpr long long int llround(@\placeholder{floating-point-type}@ x); constexpr long long int llroundf(float x); constexpr long long int llroundl(long double x); - constexpr float trunc(float x); // see \ref{library.c} - constexpr double trunc(double x); - constexpr long double trunc(long double x); // see \ref{library.c} + constexpr @\placeholder{floating-point-type}@ trunc(@\placeholder{floating-point-type}@ x); constexpr float truncf(float x); constexpr long double truncl(long double x); - constexpr float fmod(float x, float y); // see \ref{library.c} - constexpr double fmod(double x, double y); - constexpr long double fmod(long double x, long double y); // see \ref{library.c} + 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 float remainder(float x, float y); // see \ref{library.c} - constexpr double remainder(double x, double y); - constexpr long double remainder(long double x, long double y); // see \ref{library.c} + 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 float remquo(float x, float y, int* quo); // see \ref{library.c} - constexpr double remquo(double x, double y, int* quo); - constexpr long double remquo(long double x, long double y, int* quo); // see \ref{library.c} + 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 float copysign(float x, float y); // see \ref{library.c} - constexpr double copysign(double x, double y); - constexpr long double copysign(long double x, long double y); // see \ref{library.c} + 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); @@ -9345,202 +9156,156 @@ float nanf(const char* tagp); long double nanl(const char* tagp); - constexpr float nextafter(float x, float y); // see \ref{library.c} - constexpr double nextafter(double x, double y); - constexpr long double nextafter(long double x, long double y); // see \ref{library.c} + 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 float nexttoward(float x, long double y); // see \ref{library.c} - constexpr double nexttoward(double x, long double y); - constexpr long double nexttoward(long double x, long double y); // see \ref{library.c} + constexpr @\placeholder{floating-point-type}@ nexttoward(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y); constexpr float nexttowardf(float x, long double y); constexpr long double nexttowardl(long double x, long double y); - constexpr float fdim(float x, float y); // see \ref{library.c} - constexpr double fdim(double x, double y); - constexpr long double fdim(long double x, long double y); // see \ref{library.c} + 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 float fmax(float x, float y); // see \ref{library.c} - constexpr double fmax(double x, double y); - constexpr long double fmax(long double x, long double y); // see \ref{library.c} + 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 float fmin(float x, float y); // see \ref{library.c} - constexpr double fmin(double x, double y); - constexpr long double fmin(long double x, long double y); // see \ref{library.c} + 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 float fma(float x, float y, float z); // see \ref{library.c} - constexpr double fma(double x, double y, double z); - constexpr long double fma(long double x, long double y, long double z); // see \ref{library.c} + 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); // \ref{c.math.lerp}, linear interpolation - constexpr float lerp(float a, float b, float t) noexcept; - constexpr double lerp(double a, double b, double t) noexcept; - constexpr long double lerp(long double a, long double b, long double t) noexcept; + constexpr @\placeholder{floating-point-type}@ lerp(@\placeholder{floating-point-type}@ a, @\placeholder{floating-point-type}@ b, + @\placeholder{floating-point-type}@ t) noexcept; // \ref{c.math.fpclass}, classification / comparison functions - constexpr int fpclassify(float x); - constexpr int fpclassify(double x); - constexpr int fpclassify(long double x); - - constexpr bool isfinite(float x); - constexpr bool isfinite(double x); - constexpr bool isfinite(long double x); - - constexpr bool isinf(float x); - constexpr bool isinf(double x); - constexpr bool isinf(long double x); - - constexpr bool isnan(float x); - constexpr bool isnan(double x); - constexpr bool isnan(long double x); - - constexpr bool isnormal(float x); - constexpr bool isnormal(double x); - constexpr bool isnormal(long double x); - - constexpr bool signbit(float x); - constexpr bool signbit(double x); - constexpr bool signbit(long double x); - - constexpr bool isgreater(float x, float y); - constexpr bool isgreater(double x, double y); - constexpr bool isgreater(long double x, long double y); - - constexpr bool isgreaterequal(float x, float y); - constexpr bool isgreaterequal(double x, double y); - constexpr bool isgreaterequal(long double x, long double y); - - constexpr bool isless(float x, float y); - constexpr bool isless(double x, double y); - constexpr bool isless(long double x, long double y); - - constexpr bool islessequal(float x, float y); - constexpr bool islessequal(double x, double y); - constexpr bool islessequal(long double x, long double y); - - constexpr bool islessgreater(float x, float y); - constexpr bool islessgreater(double x, double y); - constexpr bool islessgreater(long double x, long double y); - - constexpr bool isunordered(float x, float y); - constexpr bool isunordered(double x, double y); - constexpr bool isunordered(long double x, long double y); + 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); // \ref{sf.cmath}, mathematical special functions // \ref{sf.cmath.assoc.laguerre}, associated Laguerre polynomials - double assoc_laguerre(unsigned n, unsigned m, double x); + @\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); // \ref{sf.cmath.assoc.legendre}, associated Legendre functions - double assoc_legendre(unsigned l, unsigned m, double x); + @\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); // \ref{sf.cmath.beta}, beta function - double beta(double x, double y); + @\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); // \ref{sf.cmath.comp.ellint.1}, complete elliptic integral of the first kind - double comp_ellint_1(double k); + @\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); // \ref{sf.cmath.comp.ellint.2}, complete elliptic integral of the second kind - double comp_ellint_2(double k); + @\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); // \ref{sf.cmath.comp.ellint.3}, complete elliptic integral of the third kind - double comp_ellint_3(double k, double nu); + @\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); // \ref{sf.cmath.cyl.bessel.i}, regular modified cylindrical Bessel functions - double cyl_bessel_i(double nu, double x); + @\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); // \ref{sf.cmath.cyl.bessel.j}, cylindrical Bessel functions of the first kind - double cyl_bessel_j(double nu, double x); + @\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); // \ref{sf.cmath.cyl.bessel.k}, irregular modified cylindrical Bessel functions - double cyl_bessel_k(double nu, double x); + @\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); - // \ref{sf.cmath.cyl.neumann}, cylindrical Neumann functions; + // \ref{sf.cmath.cyl.neumann}, cylindrical Neumann functions // cylindrical Bessel functions of the second kind - double cyl_neumann(double nu, double x); + @\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); // \ref{sf.cmath.ellint.1}, incomplete elliptic integral of the first kind - double ellint_1(double k, double phi); + @\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); // \ref{sf.cmath.ellint.2}, incomplete elliptic integral of the second kind - double ellint_2(double k, double phi); + @\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); // \ref{sf.cmath.ellint.3}, incomplete elliptic integral of the third kind - double ellint_3(double k, double nu, double phi); + @\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); // \ref{sf.cmath.expint}, exponential integral - double expint(double x); + @\placeholder{floating-point-type}@ expint(@\placeholder{floating-point-type}@ x); float expintf(float x); long double expintl(long double x); // \ref{sf.cmath.hermite}, Hermite polynomials - double hermite(unsigned n, double x); + @\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); // \ref{sf.cmath.laguerre}, Laguerre polynomials - double laguerre(unsigned n, double x); + @\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); // \ref{sf.cmath.legendre}, Legendre polynomials - double legendre(unsigned l, double x); + @\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); // \ref{sf.cmath.riemann.zeta}, Riemann zeta function - double riemann_zeta(double x); + @\placeholder{floating-point-type}@ riemann_zeta(@\placeholder{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 - double sph_bessel(unsigned n, double x); + @\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); // \ref{sf.cmath.sph.legendre}, spherical associated Legendre functions - double sph_legendre(unsigned l, unsigned m, double theta); + @\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); // \ref{sf.cmath.sph.neumann}, spherical Neumann functions; // spherical Bessel functions of the second kind - double sph_neumann(unsigned n, double x); + @\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); } @@ -9559,33 +9324,30 @@ \end{note} \pnum -For each set of overloaded functions within \libheader{cmath}, -with the exception of \tcode{abs}, -there shall be additional overloads sufficient to ensure: -\begin{itemize} - \item If any argument of arithmetic type - corresponding to a \tcode{double} parameter - has type \tcode{long double}, - then all arguments of arithmetic type\iref{basic.fundamental} - corresponding to \tcode{double} parameters - are effectively cast to \tcode{long double}. - \item Otherwise, if any argument of arithmetic type - corresponding to a \tcode{double} parameter - has type \tcode{double} - or an integer type, - then all arguments of arithmetic type - corresponding to \tcode{double} parameters - are effectively cast to \tcode{double}. - \item -\begin{note} -Otherwise, all arguments of arithmetic type -corresponding to \tcode{double} parameters -have type \tcode{float}. -\end{note} -\end{itemize} -\begin{note} -\tcode{abs} is exempted from these rules in order to stay compatible with C. -\end{note} +For each function +with at least one parameter of type \placeholder{floating-point-type}, +the implementation provides +an overload for each cv-unqualified floating-point type\iref{basic.fundamental} +where all uses of \placeholder{floating-point-type} in the function signature +are replaced with that floating-point type. + +\pnum +For each function +with at least one parameter of type \placeholder{floating-point-type} +other than \tcode{abs}, +the implementation also provides additional overloads sufficient to ensure that, +if every argument corresponding to +a \placeholder{floating-point-type} parameter has arithmetic type, +then every such argument is effectively cast to the floating-point type +with the greatest floating-point conversion rank and +greatest floating-point conversion subrank +among the types of all such arguments, +where arguments of integer type are considered to have +the same floating-point conversion rank as \tcode{double}. +If no such floating-point type with the greatest rank and subrank exists, +then overload resolution does not result in +a usable candidate\iref{over.match.general} +from the overloads provided by the implementation. \xrefc{7.12} @@ -9603,22 +9365,18 @@ constexpr int abs(int j); constexpr long int abs(long int j); constexpr long long int abs(long long int j); -constexpr float abs(float j); -constexpr double abs(double j); -constexpr long double abs(long double j); \end{itemdecl} \begin{itemdescr} \pnum \effects -The \tcode{abs} +These functions have the semantics specified in the C standard library -for the functions \tcode{abs}, \tcode{labs}, \tcode{llabs}, -\tcode{fabsf}, \tcode{fabs}, and \tcode{fabsl}. +for the functions \tcode{abs}, \tcode{labs}, and \tcode{llabs}, respectively. \pnum \remarks -If \tcode{abs()} is called with an argument of type \tcode{X} +If \tcode{abs} is called with an argument of type \tcode{X} for which \tcode{is_unsigned_v} is \tcode{true} and if \tcode{X} cannot be converted to \tcode{int} by integral promotion\iref{conv.prom}, the program is ill-formed. @@ -9627,15 +9385,23 @@ \end{note} \end{itemdescr} +\begin{itemdecl} +constexpr @\placeholder{floating-point-type}@ abs(@\placeholder{floating-point-type}@ x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The absolute value of \tcode{x}. +\end{itemdescr} + \xrefc{7.12.7.2, 7.22.6.1} \rSec2[c.math.hypot3]{Three-dimensional hypotenuse} \indexlibrary{\idxcode{hypot}!3-argument form}% \begin{itemdecl} -float hypot(float x, float y, float z); -double hypot(double x, double y, double z); -long double hypot(long double x, long double y, long double z); +@\placeholder{floating-point-type}@ hypot(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y, double z); \end{itemdecl} \begin{itemdescr} @@ -9648,9 +9414,8 @@ \indexlibraryglobal{lerp}% \begin{itemdecl} -constexpr float lerp(float a, float b, float t) noexcept; -constexpr double lerp(double a, double b, double t) noexcept; -constexpr long double lerp(long double a, long double b, long double t) noexcept; +constexpr @\placeholder{floating-point-type}@ lerp(@\placeholder{floating-point-type}@ a, @\placeholder{floating-point-type}@ b, + @\placeholder{floating-point-type}@ t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum @@ -9682,7 +9447,6 @@ \pnum The classification / comparison functions behave the same as the C macros with the corresponding names defined in the C standard library. -Each function is overloaded for the three floating-point types. \xrefc{7.12.3, 7.12.4} @@ -9747,7 +9511,7 @@ \indextext{Laguerre polynomials!$\mathsf{L}_n^m$}% \indextext{L nm@$\mathsf{L}_n^m$ (associated Laguerre polynomials)}% \begin{itemdecl} -double assoc_laguerre(unsigned n, unsigned m, double x); +@\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); \end{itemdecl} @@ -9784,7 +9548,7 @@ \indextext{Legendre polynomials!$\mathsf{P}_\ell^m$}% \indextext{P lm@$\mathsf{P}_\ell^m$ (associated Legendre polynomials)}% \begin{itemdecl} -double assoc_legendre(unsigned l, unsigned m, double x); +@\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); \end{itemdecl} @@ -9822,7 +9586,7 @@ \indextext{Eulerian integral of the first kind|see{beta functions $\mathsf{B}$}}% \indextext{beta functions $\mathsf{B}$}% \begin{itemdecl} -double beta(double x, double y); +@\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); \end{itemdecl} @@ -9851,7 +9615,7 @@ \indextext{elliptic integrals!complete $\mathsf{K}$}% \indextext{K complete@$\mathsf{K}$ (complete elliptic integrals)}% \begin{itemdecl} -double comp_ellint_1(double k); +@\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); \end{itemdecl} @@ -9881,7 +9645,7 @@ \indextext{elliptic integrals!complete $\mathsf{E}$}% \indextext{E complete@$\mathsf{E}$ (complete elliptic integrals)}% \begin{itemdecl} -double comp_ellint_2(double k); +@\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); \end{itemdecl} @@ -9911,7 +9675,7 @@ \indextext{elliptic integrals!complete $\mathsf{\Pi}$}% \indextext{Pi complete@$\mathsf{\Pi}$ (complete elliptic integrals)}% \begin{itemdecl} -double comp_ellint_3(double k, double nu); +@\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); \end{itemdecl} @@ -9942,7 +9706,7 @@ \indextext{Bessel functions!$\mathsf{I}_\nu$}% \indextext{I nu@$\mathsf{I}_\nu$ (Bessell functions)}% \begin{itemdecl} -double cyl_bessel_i(double nu, double x); +@\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); \end{itemdecl} @@ -9982,7 +9746,7 @@ \indextext{Bessel functions!$\mathsf{J}_\nu$}% \indextext{J nu@$\mathsf{J}_\nu$ (Bessell functions)}% \begin{itemdecl} -double cyl_bessel_j(double nu, double x); +@\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); \end{itemdecl} @@ -10019,7 +9783,7 @@ \indextext{Bessel functions!$\mathsf{K}_\nu$}% \indextext{K nu@$\mathsf{K}_\nu$ (Bessell functions)}% \begin{itemdecl} -double cyl_bessel_k(double nu, double x); +@\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); \end{itemdecl} @@ -10080,7 +9844,7 @@ \indextext{Neumann functions!$\mathsf{N}_\nu$}% \indextext{N nu@$\mathsf{N}_\nu$ (Neumann functions)}% \begin{itemdecl} -double cyl_neumann(double nu, double x); +@\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); \end{itemdecl} @@ -10134,7 +9898,7 @@ \indextext{elliptic integrals!incomplete $\mathsf{F}$}% \indextext{F incomplete@$\mathsf{F}$ (incomplete elliptic integrals)}% \begin{itemdecl} -double ellint_1(double k, double phi); +@\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); \end{itemdecl} @@ -10164,7 +9928,7 @@ \indextext{elliptic integrals!incomplete $\mathsf{E}$}% \indextext{E incomplete@$\mathsf{E}$ (incomplete elliptic integrals)}% \begin{itemdecl} -double ellint_2(double k, double phi); +@\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); \end{itemdecl} @@ -10193,7 +9957,8 @@ \indextext{elliptic integrals!incomplete $\mathsf{\Pi}$}% \indextext{Pi incomplete@$\mathsf{\Pi}$ (incomplete elliptic integrals)}% \begin{itemdecl} -double ellint_3(double k, double nu, double phi); +@\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); \end{itemdecl} @@ -10224,7 +9989,7 @@ \indextext{exponential integrals $\mathsf{Ei}$}% \indextext{Ei@$\mathsf{Ei}$ (exponential integrals)}% \begin{itemdecl} -double expint(double x); +@\placeholder{floating-point-type}@ expint(@\placeholder{floating-point-type}@ x); float expintf(float x); long double expintl(long double x); \end{itemdecl} @@ -10257,7 +10022,7 @@ \indextext{Hermite polynomials $\mathsf{H}_n$}% \indextext{H n@$\mathsf{H}_n$ (Hermite polynomials)}% \begin{itemdecl} -double hermite(unsigned n, double x); +@\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); \end{itemdecl} @@ -10295,7 +10060,7 @@ \indextext{Laguerre polynomials!$\mathsf{L}_n$}% \indextext{L n@$\mathsf{L}_n$ (Laguerre polynomials)}% \begin{itemdecl} -double laguerre(unsigned n, double x); +@\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); \end{itemdecl} @@ -10330,7 +10095,7 @@ \indextext{Legendre polynomials!$\mathsf{P}_\ell$}% \indextext{P l@$\mathsf{P}_\ell$ (Legendre polynomials)}% \begin{itemdecl} -double legendre(unsigned l, double x); +@\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); \end{itemdecl} @@ -10365,7 +10130,7 @@ \indexlibraryglobal{riemann_zetal}% \indextext{zeta functions $\zeta$}% \begin{itemdecl} -double riemann_zeta(double x); +@\placeholder{floating-point-type}@ riemann_zeta(@\placeholder{floating-point-type}@ x); float riemann_zetaf(float x); long double riemann_zetal(long double x); \end{itemdecl} @@ -10414,7 +10179,7 @@ \indextext{Bessel functions!$\mathsf{j}_n$}% \indextext{j n@$\mathsf{j}_n$ (spherical Bessel functions)}% \begin{itemdecl} -double sph_bessel(unsigned n, double x); +@\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); \end{itemdecl} @@ -10452,7 +10217,7 @@ \indextext{Legendre functions $\mathsf{Y}_\ell^m$}% \indextext{Y lm@$\mathsf{Y}_\ell^m$ (spherical associated Legendre functions)}% \begin{itemdecl} -double sph_legendre(unsigned l, unsigned m, double theta); +@\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); \end{itemdecl} @@ -10496,7 +10261,7 @@ \indextext{Neumann functions!$\mathsf{n}_n$}% \indextext{n n spherical@$\mathsf{n}_n$ (spherical Neumann functions)}% \begin{itemdecl} -double sph_neumann(unsigned n, double x); +@\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); \end{itemdecl} diff --git a/source/overloading.tex b/source/overloading.tex index 516ef0ed39..a43a964b5c 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -632,7 +632,7 @@ String operator + (const String&, const String&); void f() { - const char* p= "one" + "two"; // error: cannot add two pointers; overloaded \tcode{operator+} not considered + const char* p= "one" + "two"; // error: cannot add two pointers; overloaded \tcode{\keyword{operator}+} not considered // because neither operand has class or enumeration type int I = 1 + 1; // always evaluates to \tcode{2} even if class or enumeration types exist // that would perform the operation. @@ -755,13 +755,15 @@ For the \tcode{!=} operator\iref{expr.eq}, the rewritten candidates include all non-rewritten candidates -for the expression \tcode{x == y}. +for the expression \tcode{x == y} +that are rewrite targets with first operand \tcode{x} (see below). \item For the equality operators, the rewritten candidates also include a synthesized candidate, with the order of the two parameters reversed, for each non-rewritten candidate -for the expression \tcode{y == x}. +for the expression \tcode{y == x} +that is a rewrite target with first operand \tcode{y}. \item For all other operators, the rewritten candidate set is empty. \end{itemize} @@ -772,6 +774,49 @@ \end{note} \end{itemize} +\pnum +A non-template function or function template \tcode{F} named \tcode{\keyword{operator}==} +is a rewrite target with first operand \tcode{o} +unless a search for the name \tcode{\keyword{operator}!=} in the scope $S$ +from the instantiation context of the operator expression +finds a function or function template +that would correspond\iref{basic.scope.scope} to \tcode{F} +if its name were \tcode{\keyword{operator}==}, +where $S$ is the scope of the class type of \tcode{o} +if \tcode{F} is a class member, and +the namespace scope of which \tcode{F} is a member otherwise. +A function template specialization named \tcode{\keyword{operator}==} is a rewrite target +if its function template is a rewrite target. +\begin{example} +\begin{codeblock} +struct A {}; +template bool operator==(A, T); // \#1 +bool a1 = 0 == A(); // OK, calls reversed \#1 +template bool operator!=(A, T); +bool a2 = 0 == A(); // error, \#1 is not a rewrite target + +struct B { + bool operator==(const B&); // \#2 +}; +struct C : B { + C(); + C(B); + bool operator!=(const B&); // \#3 +}; +bool c1 = B() == C(); // OK, calls \#2; reversed \#2 is not a candidate + // because search for \tcode{\keyword{operator}!=} in \tcode{C} finds \#3 +bool c2 = C() == B(); // error: ambiguous between \#2 found when searching \tcode{C} and + // reversed \#2 found when searching \tcode{B} + +struct D {}; +template bool operator==(D, T); // \#4 +inline namespace N { + template bool operator!=(D, T); // \#5 +} +bool d1 = 0 == D(); // OK, calls reversed \#4; \#5 does not forbid \#4 as a rewrite target +\end{codeblock} +\end{example} + \pnum For the built-in assignment operators, conversions of the left operand are restricted as follows: @@ -1229,6 +1274,69 @@ the trailing sequence of parameters corresponding to a trailing aggregate element that is a pack expansion (if any) is replaced by a single parameter of the form $\tcode{T}_n \tcode{...}$. +In addition, +if \tcode{C} is defined and +inherits constructors\iref{namespace.udecl} +from a direct base class denoted in the \grammarterm{base-specifier-list} +by a \grammarterm{class-or-decltype} \tcode{B}, +let \tcode{A} be an alias template +whose template parameter list is that of \tcode{C} and +whose \grammarterm{defining-type-id} is \tcode{B}. +%% FIXME: the following sentence is very hard to follow; rewrite! +If \tcode{A} is a deducible template\iref{dcl.type.simple}, +the set contains the guides of \tcode{A} +with the return type \tcode{R} of each guide +replaced with \tcode{typename CC::type} given a class template +\begin{codeblock} +template class CC; +\end{codeblock} +whose primary template is not defined and +with a single partial specialization +whose template parameter list is that of \tcode{A} and +whose template argument list is a specialization of \tcode{A} with +the template argument list of \tcode{A}\iref{temp.dep.type} +having a member typedef \tcode{type} designating a template specialization with +the template argument list of \tcode{A} but +with \tcode{C} as the template. +\begin{note} +Equivalently, +the template parameter list of the specialization is that of \tcode{C}, +the template argument list of the specialization is \tcode{B}, and +the member typedef names \tcode{C} with the template argument list of \tcode{C}. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} +template struct B { + B(T); +}; +template struct C : public B { + using B::B; +}; +template struct D : public B {}; + +C c(42); // OK, deduces \tcode{C} +D d(42); // error: deduction failed, no inherited deduction guides +B(int) -> B; +C c2(42); // OK, deduces \tcode{C} + +template struct E : public B { + using B::B; +}; + +E e(42); // error: deduction failed, arguments of \tcode{E} cannot be deduced from introduced guides + +template struct F { + F(T, U, V); +}; +template struct G : F { + using G::F::F; +} + +G g(true, 'a', 1); // OK, deduces \tcode{G} +\end{codeblock} +\end{example} \pnum When resolving a placeholder for a deduced class type\iref{dcl.type.simple} @@ -1414,7 +1522,7 @@ F f1 = {Types{}, {}, {}}; // OK, \tcode{F} deduced F f2 = {Types{}, X{}, Y{}}; // OK, \tcode{F} deduced -F f3 = {Types{}, X{}, W{}}; // error: conflicting types deduced; \tcode{operator Y} not considered +F f3 = {Types{}, X{}, W{}}; // error: conflicting types deduced; \tcode{\keyword{operator} Y} not considered \end{codeblock} \end{example} @@ -1447,7 +1555,7 @@ template concept deduces_A = requires { sizeof(AA); }; // \tcode{f1} is formed from the constructor \#1 of \tcode{C}, generating the following function template -template +template auto f1(T, U) -> C; // Deducing arguments for \tcode{C} from \tcode{C} deduces \tcode{T} as \tcode{V *} and \tcode{U} as \tcode{V *}; @@ -1550,31 +1658,14 @@ \pnum \indextext{conversion!overload resolution and}% -Define $\text{ICS}^i(\tcode{F})$ as follows: -\begin{itemize} -\item -If \tcode{F} is a static member function, -$\text{ICS}^1(\tcode{F})$ is defined such that -$\text{ICS}^1(\tcode{F})$ is neither better nor worse than -$\text{ICS}^1(\tcode{G})$ for any function \tcode{G}, -and, symmetrically, $\text{ICS}^1(\tcode{G})$ is neither better nor worse than -$\text{ICS}^1(\tcode{F})$; -\begin{footnote} -If a function is a static member function, this -definition means that the first argument, the implied object argument, -has no effect in the determination of whether the function is better -or worse than any other function. -\end{footnote} -otherwise, -\item -let $\text{ICS}^i(\tcode{F})$ denote the implicit conversion sequence that converts +Define $\text{ICS}^i(\tcode{F})$ as +the implicit conversion sequence that converts the $i^\text{th}$ argument in the list to the type of the $i^\text{th}$ parameter of viable function \tcode{F}. \ref{over.best.ics} defines the implicit conversion sequences and \ref{over.ics.rank} defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another. -\end{itemize} \pnum Given these definitions, @@ -1713,6 +1804,18 @@ \end{example} or, if not that +\item +\tcode{F1} and \tcode{F2} are generated +from class template argument deduction\iref{over.match.class.deduct} +for a class \tcode{D}, and +\tcode{F2} is generated +from inheriting constructors from a base class of \tcode{D} +while \tcode{F1} is not, and +for each explicit function argument, +the corresponding parameters of \tcode{F1} and \tcode{F2} +are either both ellipses or have the same type, +or, if not that, + \item \tcode{F1} is generated from a \grammarterm{deduction-guide}\iref{over.match.class.deduct} @@ -1809,7 +1912,7 @@ // and \tcode{1L} $\to$ \tcode{short} and \tcode{1L} $\to$ \tcode{int} are indistinguishable Fcn(&i, 'c'); // calls \tcode{Fcn(int*, int)}, because \tcode{\&i} $\to$ \tcode{int*} is better than \tcode{\&i} $\to$ \tcode{const int*} - // and \tcode{c} $\to$ \tcode{int} is better than \tcode{c} $\to$ \tcode{short} + // and \tcode{'c'} $\to$ \tcode{int} is better than \tcode{'c'} $\to$ \tcode{short} } \end{codeblock} \end{example} @@ -1960,6 +2063,9 @@ only in the description of implicit conversion sequences. \end{note} A derived-to-base conversion has Conversion rank\iref{over.ics.scs}. +When the parameter is the implicit object parameter of a static member function, +the implicit conversion sequence is a standard conversion sequence +that is neither better nor worse than any other standard conversion sequence. \pnum In all contexts, when converting to the implicit object parameter @@ -2675,6 +2781,34 @@ A conversion that promotes an enumeration whose underlying type is fixed to its underlying type is better than one that promotes to the promoted underlying type, if the two are different. +\item +A conversion in either direction +between floating-point type \tcode{FP1} and floating-point type \tcode{FP2} +is better than a conversion in the same direction +between \tcode{FP1} and arithmetic type \tcode{T3} if +\begin{itemize} +\item +the floating-point conversion rank\iref{conv.rank} of \tcode{FP1} +is equal to the rank of \tcode{FP2}, and +\item +\tcode{T3} is not a floating-point type, or +\tcode{T3} is a floating-point type +whose rank is not equal to the rank of \tcode{FP1}, or +the floating-point conversion subrank\iref{conv.rank} of \tcode{FP2} +is greater than the subrank of \tcode{T3}. +\begin{example} +\begin{codeblock} +int f(std::float32_t); +int f(std::float64_t); +int f(long long); +float x; +std::float16_t y; +int i = f(x); // calls \tcode{f(std::float32_t)} on implementations where + // \tcode{float} and \tcode{std::float32_t} have equal conversion ranks +int j = f(y); // error: ambiguous, no equal conversion rank +\end{codeblock} +\end{example} +\end{itemize} \item If class @@ -3077,9 +3211,15 @@ \pnum \indextext{restriction!overloading}% An operator function -shall either be a non-static member function or be a non-member function that +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 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 @@ -3265,7 +3405,7 @@ \pnum A \defnadj{function call}{operator function} is a function named \tcode{\keyword{operator}()} -that is a non-static member function with an arbitrary number of parameters. +that is a member function with an arbitrary number of parameters. It may have default arguments. For an expression of the form \begin{ncsimplebnf} @@ -3292,7 +3432,8 @@ \pnum A \defnadj{subscripting}{operator function} is a function named \tcode{\keyword{operator}[]} -that is a non-static member function. +that is a non-static member function with an arbitrary number of parameters. +It may have default arguments. For an expression of the form \begin{ncsimplebnf} postfix-expression \terminal{[} \opt{expression-list} \terminal{]} diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 7528bd6c83..af42cac023 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -56,6 +56,7 @@ \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 \end{bnf} @@ -1603,18 +1604,21 @@ one of the two previous forms, the behavior is undefined; otherwise, the result is processed as appropriate. -\rSec1[cpp.error]{Error directive}% +\rSec1[cpp.error]{Diagnostic directives}% \indextext{preprocessing directive!error}% +\indextext{preprocessing directive!diagnostic}% +\indextext{preprocessing directive!warning}% \indextext{\idxcode{\#error}|see{preprocessing directive, error}} \pnum -A preprocessing directive of the form +A preprocessing directive of either of the following forms \begin{ncsimplebnf} -\terminal{\# error} \opt{pp-tokens} new-line +\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, -and renders the program ill-formed. +a diagnostic message that should include the specified sequence of preprocessing tokens; +the \tcode{\# error} directive renders the program ill-formed. \rSec1[cpp.pragma]{Pragma directive}% \indextext{preprocessing directive!pragma}% @@ -1724,6 +1728,45 @@ \tcode{operator new(std::size_t, std::align_val_t)}, etc.\iref{expr.new}. \end{note} +\item +\indextext{__stdcpp_float16_t__@\mname{STDCPP_FLOAT16_T}}% +\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 +as an extended floating-point type\iref{basic.extended.fp}. + +\item +\indextext{__stdcpp_float32_t__@\mname{STDCPP_FLOAT32_T}}% +\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 +as an extended floating-point type. + +\item +\indextext{__stdcpp_float64_t__@\mname{STDCPP_FLOAT64_T}}% +\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 +as an extended floating-point type. + +\item +\indextext{__stdcpp_float128_t__@\mname{STDCPP_FLOAT128_T}}% +\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 +as an extended floating-point type. + +\item +\indextext{__stdcpp_bfloat16_t__@\mname{STDCPP_BFLOAT16_T}}% +\mname{STDCPP_BFLOAT16_T}\\ +Defined as the integer literal \tcode{1} +if and only if the implementation supports an extended floating-point type +with the properties described in \ref{basic.extended.fp}. + \item \indextext{__time__@\mname{TIME}}% \mname{TIME}\\ @@ -1753,10 +1796,10 @@ \defnxname{cpp_attributes} & \tcode{200809L} \\ \rowsep \defnxname{cpp_binary_literals} & \tcode{201304L} \\ \rowsep \defnxname{cpp_capture_star_this} & \tcode{201603L} \\ \rowsep -\defnxname{cpp_char8_t} & \tcode{201811L} \\ \rowsep +\defnxname{cpp_char8_t} & \tcode{202207L} \\ \rowsep \defnxname{cpp_concepts} & \tcode{202002L} \\ \rowsep \defnxname{cpp_conditional_explicit} & \tcode{201806L} \\ \rowsep -\defnxname{cpp_constexpr} & \tcode{202110L} \\ \rowsep +\defnxname{cpp_constexpr} & \tcode{202207L} \\ \rowsep \defnxname{cpp_constexpr_dynamic_alloc} & \tcode{201907L} \\ \rowsep \defnxname{cpp_constexpr_in_decltype} & \tcode{201711L} \\ \rowsep \defnxname{cpp_consteval} & \tcode{201811L} \\ \rowsep @@ -1777,6 +1820,7 @@ \defnxname{cpp_impl_coroutine} & \tcode{201902L} \\ \rowsep \defnxname{cpp_impl_destroying_delete} & \tcode{201806L} \\ \rowsep \defnxname{cpp_impl_three_way_comparison} & \tcode{201907L} \\ \rowsep +\defnxname{cpp_implicit_move} & \tcode{202207L} \\ \rowsep \defnxname{cpp_inheriting_constructors} & \tcode{201511L} \\ \rowsep \defnxname{cpp_init_captures} & \tcode{201803L} \\ \rowsep \defnxname{cpp_initializer_lists} & \tcode{200806L} \\ \rowsep @@ -1784,6 +1828,7 @@ \defnxname{cpp_lambdas} & \tcode{200907L} \\ \rowsep \defnxname{cpp_modules} & \tcode{201907L} \\ \rowsep \defnxname{cpp_multidimensional_subscript} & \tcode{202110L} \\ \rowsep +\defnxname{cpp_named_character_escapes} & \tcode{202207L} \\ \rowsep \defnxname{cpp_namespace_attributes} & \tcode{201411L} \\ \rowsep \defnxname{cpp_noexcept_function_type} & \tcode{201510L} \\ \rowsep \defnxname{cpp_nontype_template_args} & \tcode{201911L} \\ \rowsep @@ -1797,6 +1842,7 @@ \defnxname{cpp_size_t_suffix} & \tcode{202011L} \\ \rowsep \defnxname{cpp_sized_deallocation} & \tcode{201309L} \\ \rowsep \defnxname{cpp_static_assert} & \tcode{201411L} \\ \rowsep +\defnxname{cpp_static_call_operator} & \tcode{202207L} \\ \rowsep \defnxname{cpp_structured_bindings} & \tcode{201606L} \\ \rowsep \defnxname{cpp_template_template_args} & \tcode{201611L} \\ \rowsep \defnxname{cpp_threadsafe_static_init} & \tcode{200806L} \\ \rowsep diff --git a/source/ranges.tex b/source/ranges.tex index f980dd7eca..82e0257ed3 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -10,7 +10,7 @@ The following subclauses describe range and view requirements, and components for -range primitives +range primitives and range generators as summarized in \tref{range.summary}. \begin{libsumtab}{Ranges library summary}{range.summary} @@ -18,7 +18,8 @@ \ref{range.req} & Requirements & \\ \ref{range.utility} & Range utilities & \\ \ref{range.factories} & Range factories & \\ - \ref{range.adaptors} & Range adaptors & \\ + \ref{range.adaptors} & Range adaptors & \\ \rowsep + \ref{coro.generator} & Range generators & \libheader{generator} \\ \end{libsumtab} \rSec1[ranges.syn]{Header \tcode{} synopsis} @@ -33,141 +34,166 @@ namespace std::ranges { inline namespace @\unspec@ { // \ref{range.access}, range access - 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@ ssize = @\unspec@; - inline constexpr @\unspec@ empty = @\unspec@; - inline constexpr @\unspec@ data = @\unspec@; - inline constexpr @\unspec@ cdata = @\unspec@; + 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 } // \ref{range.range}, ranges template - concept range = @\seebelow@; + concept range = @\seebelow@; // freestanding template - inline constexpr bool enable_borrowed_range = false; + inline constexpr bool enable_borrowed_range = false; // freestanding template - concept borrowed_range = @\seebelow@; + concept borrowed_range = @\seebelow@; // freestanding template - using iterator_t = decltype(ranges::begin(declval())); + using iterator_t = decltype(ranges::begin(declval())); // freestanding template<@\libconcept{range}@ R> - using sentinel_t = decltype(ranges::end(declval())); + using sentinel_t = decltype(ranges::end(declval())); // freestanding template<@\libconcept{range}@ R> - using range_difference_t = iter_difference_t>; + using const_iterator_t = const_iterator>; // freestanding + template<@\libconcept{range}@ R> + using range_difference_t = iter_difference_t>; // freestanding template<@\libconcept{sized_range}@ R> - using range_size_t = decltype(ranges::size(declval())); + using range_size_t = decltype(ranges::size(declval())); // freestanding + template<@\libconcept{range}@ R> + using range_value_t = iter_value_t>; // freestanding template<@\libconcept{range}@ R> - using range_value_t = iter_value_t>; + using range_reference_t = iter_reference_t>; // freestanding template<@\libconcept{range}@ R> - using range_reference_t = iter_reference_t>; + using range_const_reference_t = iter_const_reference_t>; // freestanding template<@\libconcept{range}@ R> - using range_rvalue_reference_t = iter_rvalue_reference_t>; + using range_rvalue_reference_t = iter_rvalue_reference_t>; // freestanding // \ref{range.sized}, sized ranges template - inline constexpr bool disable_sized_range = false; + inline constexpr bool disable_sized_range = false; // freestanding template - concept sized_range = @\seebelow@; + concept sized_range = @\seebelow@; // freestanding // \ref{range.view}, views template - inline constexpr bool enable_view = @\seebelow@; + inline constexpr bool enable_view = @\seebelow@; // freestanding - struct view_base {}; + struct view_base {}; // freestanding template - concept view = @\seebelow@; + concept view = @\seebelow@; // freestanding // \ref{range.refinements}, other range refinements template - concept output_range = @\seebelow@; + concept output_range = @\seebelow@; // freestanding + + template + concept input_range = @\seebelow@; // freestanding template - concept input_range = @\seebelow@; + concept forward_range = @\seebelow@; // freestanding template - concept forward_range = @\seebelow@; + concept bidirectional_range = @\seebelow@; // freestanding template - concept bidirectional_range = @\seebelow@; + concept random_access_range = @\seebelow@; // freestanding template - concept random_access_range = @\seebelow@; + concept contiguous_range = @\seebelow@; // freestanding template - concept contiguous_range = @\seebelow@; + concept common_range = @\seebelow@; // freestanding template - concept common_range = @\seebelow@; + concept viewable_range = @\seebelow@; // freestanding template - concept viewable_range = @\seebelow@; + concept constant_range = @\seebelow@; // freestanding // \ref{view.interface}, class template \tcode{view_interface} template requires is_class_v && @\libconcept{same_as}@> - class view_interface; + class view_interface; // freestanding // \ref{range.subrange}, sub-ranges - enum class subrange_kind : bool { unsized, sized }; + enum class subrange_kind : bool { unsized, sized }; // freestanding 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; + class subrange; // freestanding template - inline constexpr bool enable_borrowed_range> = true; + inline constexpr bool enable_borrowed_range> = true; // freestanding + + template + requires ((N == 0 && @\libconcept{copyable}@) || N == 1) + constexpr auto get(const subrange& r); + + template + requires (N < 2) + constexpr auto get(subrange&& r); +} + +namespace std { + using ranges::get; +} +namespace std::ranges { // \ref{range.dangling}, dangling iterator handling - struct dangling; + struct dangling; // freestanding + + // \ref{ranges.elementsof}, class template \tcode{elements_of} + template<@\libconcept{range}@ R, class Allocator = allocator> + struct elements_of; template<@\libconcept{range}@ R> - using borrowed_iterator_t = @\seebelow@; + using borrowed_iterator_t = @\seebelow@; // freestanding template<@\libconcept{range}@ R> - using borrowed_subrange_t = @\seebelow@; + using borrowed_subrange_t = @\seebelow@; // freestanding // \ref{range.utility.conv}, range conversions template requires (!@\libconcept{view}@) - constexpr C to(R&& r, Args&&... args); + constexpr C to(R&& r, Args&&... args); // freestanding template class C, @\libconcept{input_range}@ R, class... Args> - constexpr auto to(R&& r, Args&&... args) -> @\seebelow@; + constexpr auto to(R&& r, Args&&... args); // freestanding template requires (!@\libconcept{view}@) - constexpr auto to(Args&&... args) -> @\seebelow@; + constexpr auto to(Args&&... args); // freestanding template class C, class... Args> - constexpr auto to(Args&&... args) -> @\seebelow@; + constexpr auto to(Args&&... args); // freestanding // \ref{range.empty}, empty view template requires is_object_v - class empty_view; + class empty_view; // freestanding template - inline constexpr bool enable_borrowed_range> = true; + inline constexpr bool enable_borrowed_range> = true; // freestanding namespace views { template - inline constexpr empty_view @\libmember{empty}{views}@{}; + inline constexpr empty_view @\libmember{empty}{views}@{}; // freestanding } // \ref{range.single}, single view - template<@\libconcept{copy_constructible}@ T> + template<@\libconcept{move_constructible}@ T> requires is_object_v - class single_view; + class single_view; // freestanding - namespace views { inline constexpr @\unspec@ single = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ single = @\unspecnc@; } // freestanding template using @\exposidnc{maybe-const}@ = conditional_t; // \expos @@ -175,12 +201,20 @@ // \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; + class iota_view; // freestanding template - inline constexpr bool enable_borrowed_range> = true; + inline constexpr bool enable_borrowed_range> = true; // freestanding + + namespace views { inline constexpr @\unspecnc@ iota = @\unspecnc@; } // freestanding - namespace views { inline constexpr @\unspec@ iota = @\unspec@; } + // \ref{range.repeat}, repeat view + template<@\libconcept{move_constructible}@ W, @\libconcept{semiregular}@ Bound = unreachable_sentinel_t> + requires (is_object_v && @\libconcept{same_as}@> + && (@\exposid{is-integer-like}@ || @\libconcept{same_as}@)) + class repeat_view; + + namespace views { inline constexpr @\unspec@ repeat = @\unspec@; } // \ref{range.istream}, istream view template<@\libconcept{movable}@ Val, class CharT, class Traits = char_traits> @@ -191,95 +225,110 @@ template using wistream_view = basic_istream_view; - namespace views { template inline constexpr @\unspec@ istream = @\unspec@; } + namespace views { template inline constexpr @\unspecnc@ istream = @\unspecnc@; } // \ref{range.adaptor.object}, range adaptor objects template requires is_class_v && @\libconcept{same_as}@> - class range_adaptor_closure { }; + class range_adaptor_closure { }; // freestanding // \ref{range.all}, all view namespace views { - inline constexpr @\unspec@ all = @\unspec@; + inline constexpr @\unspecnc@ all = @\unspecnc@; // freestanding template<@\libconcept{viewable_range}@ R> - using all_t = decltype(all(declval())); + using all_t = decltype(all(declval())); // freestanding } + // \ref{range.ref.view}, ref view template<@\libconcept{range}@ R> requires is_object_v - class ref_view; + class ref_view; // freestanding template - inline constexpr bool enable_borrowed_range> = true; + inline constexpr bool enable_borrowed_range> = true; // freestanding // \ref{range.owning.view}, owning view - template + template<@\libconcept{range}@ R> requires @\seebelow@ - class owning_view; + class owning_view; // freestanding + + template + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; + + // \ref{range.as.rvalue}, as rvalue view + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + class as_rvalue_view; // freestanding template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; + + namespace views { inline constexpr @\unspecnc@ as_rvalue = @\unspecnc@; } // freestanding // \ref{range.filter}, filter view template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> requires @\libconcept{view}@ && is_object_v - class filter_view; + class filter_view; // freestanding - namespace views { inline constexpr @\unspec@ filter = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ filter = @\unspecnc@; } // freestanding // \ref{range.transform}, transform view - template<@\libconcept{input_range}@ V, @\libconcept{copy_constructible}@ F> + template<@\libconcept{input_range}@ V, @\libconcept{move_constructible}@ F> requires @\libconcept{view}@ && is_object_v && @\libconcept{regular_invocable}@> && @\exposconcept{can-reference}@>> - class transform_view; + class transform_view; // freestanding - namespace views { inline constexpr @\unspec@ transform = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ transform = @\unspecnc@; } // freestanding // \ref{range.take}, take view - template<@\libconcept{view}@> class take_view; + template<@\libconcept{view}@> class take_view; // freestanding template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; - namespace views { inline constexpr @\unspec@ take = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ take = @\unspecnc@; } // freestanding // \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; + class take_while_view; // freestanding - namespace views { inline constexpr @\unspec@ take_while = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ take_while = @\unspecnc@; } // freestanding // \ref{range.drop}, drop view template<@\libconcept{view}@ V> - class drop_view; + class drop_view; // freestanding template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; - namespace views { inline constexpr @\unspec@ drop = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ drop = @\unspecnc@; } // freestanding // \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; + class drop_while_view; // freestanding template - inline constexpr bool enable_borrowed_range> = + inline constexpr bool enable_borrowed_range> = // freestanding enable_borrowed_range; - namespace views { inline constexpr @\unspec@ drop_while = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ drop_while = @\unspecnc@; } // freestanding // \ref{range.join}, join view template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ && @\libconcept{input_range}@> - class join_view; + class join_view; // freestanding - namespace views { inline constexpr @\unspec@ join = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ join = @\unspecnc@; } // freestanding // \ref{range.join.with}, join with view template @@ -289,9 +338,9 @@ requires @\libconcept{view}@ && @\libconcept{input_range}@> && @\libconcept{view}@ && @\exposconcept{compatible-joinable-ranges}@, Pattern> - class join_with_view; + class join_with_view; // freestanding - namespace views { inline constexpr @\unspec@ join_with = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ join_with = @\unspecnc@; } // freestanding // \ref{range.lazy.split}, lazy split view template @@ -301,170 +350,210 @@ requires @\libconcept{view}@ && @\libconcept{view}@ && @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) - class lazy_split_view; + class lazy_split_view; // freestanding // \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; + class split_view; // freestanding namespace views { - inline constexpr @\unspec@ lazy_split = @\unspec@; - inline constexpr @\unspec@ split = @\unspec@; + inline constexpr @\unspecnc@ lazy_split = @\unspecnc@; // freestanding + inline constexpr @\unspecnc@ split = @\unspecnc@; // freestanding } // \ref{range.counted}, counted view - namespace views { inline constexpr @\unspec@ counted = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ counted = @\unspecnc@; } // freestanding // \ref{range.common}, common view template<@\libconcept{view}@ V> requires (!@\libconcept{common_range}@ && @\libconcept{copyable}@>) - class common_view; + class common_view; // freestanding template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; - namespace views { inline constexpr @\unspec@ common = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ common = @\unspecnc@; } // freestanding // \ref{range.reverse}, reverse view template<@\libconcept{view}@ V> requires @\libconcept{bidirectional_range}@ - class reverse_view; + class reverse_view; // freestanding + + template + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; + + namespace views { inline constexpr @\unspecnc@ reverse = @\unspecnc@; } // freestanding + + // \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}@) { + return const_cast(r); + } else { + return r; + } + } + + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + class as_const_view; // freestanding template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; - namespace views { inline constexpr @\unspec@ reverse = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ as_const = @\unspecnc@; } // freestanding // \ref{range.elements}, elements view template<@\libconcept{input_range}@ V, size_t N> requires @\seebelow@ - class elements_view; + class elements_view; // freestanding template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + inline constexpr bool enable_borrowed_range> = // freestanding + enable_borrowed_range; template - using @\libglobal{keys_view}@ = elements_view; + using @\libglobal{keys_view}@ = elements_view; // freestanding template - using @\libglobal{values_view}@ = elements_view; + using @\libglobal{values_view}@ = elements_view; // freestanding namespace views { template - inline constexpr @\unspec@ elements = @\unspec@; - inline constexpr auto @\libmember{keys}{views}@ = elements<0>; - inline constexpr auto @\libmember{values}{views}@ = elements<1>; + inline constexpr @\unspecnc@ elements = @\unspecnc@; // freestanding + inline constexpr auto @\libmember{keys}{views}@ = elements<0>; // freestanding + inline constexpr auto @\libmember{values}{views}@ = elements<1>; // freestanding } // \ref{range.zip}, zip view template<@\libconcept{input_range}@... Views> requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) - class zip_view; + class zip_view; // freestanding template - inline constexpr bool enable_borrowed_range> = + inline constexpr bool enable_borrowed_range> = // freestanding (enable_borrowed_range && ...); - namespace views { inline constexpr @\unspec@ zip = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ zip = @\unspecnc@; } // freestanding // \ref{range.zip.transform}, zip transform view - template<@\libconcept{copy_constructible}@ F, @\libconcept{input_range}@... Views> + 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; + class zip_transform_view; // freestanding - namespace views { inline constexpr @\unspec@ zip_transform = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ zip_transform = @\unspecnc@; } // freestanding // \ref{range.adjacent}, adjacent view template<@\libconcept{forward_range}@ V, size_t N> requires @\libconcept{view}@ && (N > 0) - class adjacent_view; + class adjacent_view; // freestanding template - inline constexpr bool enable_borrowed_range> = + inline constexpr bool enable_borrowed_range> = // freestanding enable_borrowed_range; namespace views { template - inline constexpr @\unspec@ adjacent = @\unspec@ ; - inline constexpr auto @\libmember{pairwise}{views}@ = adjacent<2>; + inline constexpr @\unspecnc@ adjacent = @\unspecnc@; // freestanding + inline constexpr auto @\libmember{pairwise}{views}@ = adjacent<2>; // freestanding } // \ref{range.adjacent.transform}, adjacent transform view - template<@\libconcept{forward_range}@ V, @\libconcept{copy_constructible}@ F, size_t N> + template<@\libconcept{forward_range}@ V, @\libconcept{move_constructible}@ F, size_t N> requires @\seebelow@ - class adjacent_transform_view; + class adjacent_transform_view; // freestanding namespace views { template - inline constexpr @\unspec@ adjacent_transform = @\unspec@; - inline constexpr auto @\libmember{pairwise_transform}{views}@ = adjacent_transform<2>; + inline constexpr @\unspecnc@ adjacent_transform = @\unspecnc@; // freestanding + inline constexpr auto @\libmember{pairwise_transform}{views}@ = adjacent_transform<2>; // freestanding } // \ref{range.chunk}, chunk view template<@\libconcept{view}@ V> requires @\libconcept{input_range}@ - class chunk_view; + class chunk_view; // freestanding template<@\libconcept{view}@ V> requires @\libconcept{forward_range}@ - class chunk_view; + class chunk_view; // freestanding template - inline constexpr bool enable_borrowed_range> = + inline constexpr bool enable_borrowed_range> = // freestanding @\libconcept{forward_range}@ && enable_borrowed_range; - namespace views { inline constexpr @\unspec@ chunk = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ chunk = @\unspecnc@; } // freestanding // \ref{range.slide}, slide view - template<@\libconcept{view}@ V> - requires @\libconcept{forward_range}@ - class slide_view; + template<@\libconcept{forward_range}@ V> + requires @\libconcept{view}@ + class slide_view; // freestanding template inline constexpr bool enable_borrowed_range> = - enable_borrowed_range; + enable_borrowed_range; // freestanding - namespace views { inline constexpr @\unspec@ slide = @\unspec@; } + namespace views { inline constexpr @\unspecnc@ slide = @\unspecnc@; } // freestanding // \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; + class chunk_by_view; // freestanding + + namespace views { inline constexpr @\unspecnc@ chunk_by = @\unspecnc@; } // freestanding + + // \ref{range.stride}, stride view + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ + class stride_view; - namespace views { inline constexpr @\unspec@ chunk_by = @\unspec@; } + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + + 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; + + namespace views { inline constexpr @\unspecnc@ cartesian_product = @\unspecnc@; } } namespace std { - namespace views = ranges::views; + namespace views = ranges::views; // freestanding - template struct tuple_size; - template struct tuple_element; + template struct tuple_size; // freestanding + template struct tuple_element; // freestanding template - struct tuple_size> + struct tuple_size> // freestanding : integral_constant {}; template - struct tuple_element<0, ranges::subrange> { - using type = I; + struct tuple_element<0, ranges::subrange> { // freestanding + using type = I; // freestanding }; template - struct tuple_element<1, ranges::subrange> { - using type = S; + struct tuple_element<1, ranges::subrange> { // freestanding + using type = S; // freestanding }; template - struct tuple_element<0, const ranges::subrange> { - using type = I; + struct tuple_element<0, const ranges::subrange> { // freestanding + using type = I; // freestanding }; template - struct tuple_element<1, const ranges::subrange> { - using type = S; + struct tuple_element<1, const ranges::subrange> { // freestanding + using type = S; // freestanding }; - struct from_range_t { explicit from_range_t() = default; }; - inline constexpr from_range_t from_range{}; + struct from_range_t { explicit from_range_t() = default; }; // freestanding + inline constexpr from_range_t from_range{}; // freestanding } \end{codeblock} @@ -653,18 +742,26 @@ \pnum The name \tcode{ranges::cbegin} denotes a customization point -object\iref{customization.point.object}. The expression -\tcode{ranges::\brk{}cbegin(E)} for a subexpression \tcode{E} of type \tcode{T} -is expression-equivalent to: +object\iref{customization.point.object}. +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 \tcode{ranges::begin(static_cast(E))} if \tcode{E} is an lvalue. -\item Otherwise, \tcode{ranges::begin(static_cast(E))}. +\item +If \tcode{E} is an rvalue and +\tcode{enable_borrowed_range>} is \tcode{false}, +\tcode{ranges::cbegin(E)} is ill-formed. +\item +Otherwise, +let \tcode{U} be \tcode{ranges::begin(\exposid{possibly-const-range}(t))}. +\tcode{ranges::cbegin(E)} is expression-equivalent to +\tcode{const_iterator(U)}. \end{itemize} \pnum \begin{note} Whenever \tcode{ranges::cbegin(E)} is a valid expression, its type models -\libconcept{input_or_output_iterator}. +\libconcept{input_or_output_iterator} and \exposconcept{constant-iterator}. \end{note} \rSec2[range.access.cend]{\tcode{ranges::cend}} @@ -672,12 +769,20 @@ \pnum The name \tcode{ranges::cend} denotes a customization point -object\iref{customization.point.object}. The expression -\tcode{ranges::cend(E)} for a subexpression \tcode{E} of type \tcode{T} -is expression-equivalent to: +object\iref{customization.point.object}. +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 \tcode{ranges::end(static_cast(E))} if \tcode{E} is an lvalue. -\item Otherwise, \tcode{ranges::end(static_cast(E))}. +\item +If \tcode{E} is an rvalue and +\tcode{enable_borrowed_range>} is \tcode{false}, +\tcode{ranges::cend(E)} is ill-formed. +\item +Otherwise, +let \tcode{U} be \tcode{ranges::end(\exposid{possibly-const-range}(t))}. +\tcode{ranges::cend(E)} is expression-equivalent to +\tcode{const_sentinel(U)}. \end{itemize} \pnum @@ -686,6 +791,8 @@ the types \tcode{S} and \tcode{I} of the expressions \tcode{ranges::cend(E)} and \tcode{ranges::cbegin(E)} model \tcode{\libconcept{sentinel_for}}. +If \tcode{S} models \libconcept{input_iterator}, +then \tcode{S} also models \exposconceptx{constant-itera\-tor}{constant-iterator}. \end{note} \rSec2[range.access.rbegin]{\tcode{ranges::rbegin}} @@ -833,19 +940,27 @@ \pnum The name \tcode{ranges::crbegin} denotes a customization point -object\iref{customization.point.object}. The expression -\tcode{ranges::\brk{}crbegin(E)} for a subexpression \tcode{E} of type -\tcode{T} is expression-equivalent to: +object\iref{customization.point.object}. +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 \tcode{ranges::\brk{}rbegin(static_cast(E))} if \tcode{E} is - an lvalue. -\item Otherwise, \tcode{ranges::rbegin(static_cast(E))}. +\item +If \tcode{E} is an rvalue and +\tcode{enable_borrowed_range>} is \tcode{false}, +\tcode{ranges::crbegin(E)} is ill-formed. +\item +Otherwise, +let \tcode{U} be \tcode{ranges::rbegin(\exposid{possibly-const-range}(t))}. +\tcode{ranges::crbegin(E)} is expres\-sion-equivalent to +\tcode{const_iterator(U)}. \end{itemize} \pnum \begin{note} Whenever \tcode{ranges::crbegin(E)} is a valid expression, its -type models \libconcept{input_or_output_iterator}. +type models \libconcept{input_or_output_iterator} and +\exposconcept{constant-iterator}. \end{note} \rSec2[range.access.crend]{\tcode{ranges::crend}} @@ -853,13 +968,20 @@ \pnum The name \tcode{ranges::crend} denotes a customization point -object\iref{customization.point.object}. The expression -\tcode{ranges::\brk{}crend(E)} for a subexpression \tcode{E} of type \tcode{T} -is expression-equivalent to: +object\iref{customization.point.object}. +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 \tcode{ranges::rend(static_cast(E))} if \tcode{E} is an lvalue. - -\item Otherwise, \tcode{ranges::rend(static_cast(E))}. +\item +If \tcode{E} is an rvalue and +\tcode{enable_borrowed_range>} is \tcode{false}, +\tcode{ranges::crend(E)} is ill-formed. +\item +Otherwise, +let \tcode{U} be \tcode{ranges::rend(\exposid{possibly-const-range}(t))}. +\tcode{ranges::crend(E)} is expression-equivalent to +\tcode{const_sentinel(U)}. \end{itemize} \pnum @@ -868,6 +990,8 @@ the types \tcode{S} and \tcode{I} of the expressions \tcode{ranges::crend(E)} and \tcode{ranges::crbegin(E)} model \tcode{\libconcept{sentinel_for}}. +If \tcode{S} models \libconcept{input_iterator}, +then \tcode{S} also models \exposconceptx{constant-itera\-tor}{constant-iterator}. \end{note} \rSec2[range.prim.size]{\tcode{ranges::size}} @@ -1068,21 +1192,32 @@ \rSec2[range.prim.cdata]{\tcode{ranges::cdata}} \indexlibraryglobal{cdata}% +\begin{codeblock} +template +constexpr auto @\exposid{as-const-pointer}@(const T* p) { return p; } // \expos +\end{codeblock} + \pnum The name \tcode{ranges::cdata} denotes a customization point -object\iref{customization.point.object}. The expression -\tcode{ranges::\brk{}cdata(E)} for a subexpression \tcode{E} of type \tcode{T} -is expression-equivalent to: +object\iref{customization.point.object}. +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 \tcode{ranges::data(static_cast(E))} if \tcode{E} is an lvalue. - -\item Otherwise, \tcode{ranges::data(static_cast(E))}. +\item +If \tcode{E} is an rvalue and +\tcode{enable_borrowed_range>} is \tcode{false}, +\tcode{ranges::cdata(E)} is ill-formed. +\item +Otherwise, +\tcode{ranges::cdata(E)} is expression-equivalent to +\tcode{\exposid{as-const-pointer}(ranges::data(\exposid{possi\-bly-const-range}(t)))}. \end{itemize} \pnum \begin{note} Whenever \tcode{ranges::cdata(E)} is a valid expression, it -has pointer to object type. +has pointer to constant object type. \end{note} \rSec1[range.req]{Range requirements} @@ -1090,7 +1225,7 @@ \rSec2[range.req.general]{General} \pnum -Ranges are an abstraction that allow a \Cpp{} program +Ranges are an abstraction that allows a \Cpp{} program to operate on elements of data structures uniformly. Calling \tcode{ranges::begin} on a range returns an object whose type models \libconcept{input_or_output_iterator}\iref{iterator.concept.iterator}. @@ -1482,6 +1617,16 @@ (is_lvalue_reference_v || (@\libconcept{movable}@> && !@\exposid{is-initializer-list}@)))); \end{itemdecl} +\pnum +The \libconcept{constant_range} concept specifies the requirements of a +\libconcept{range} type whose elements are not modifiable. + +\begin{itemdecl} +template + concept @\deflibconcept{constant_range}@ = + @\libconcept{input_range}@ && @\exposconcept{constant-iterator}@>; +\end{itemdecl} + \rSec1[range.utility]{Range utilities} \rSec2[range.utility.general]{General} @@ -1536,11 +1681,30 @@ } public: - constexpr bool empty() requires @\libconcept{forward_range}@ { - return ranges::begin(@\exposid{derived}@()) == ranges::end(@\exposid{derived}@()); + constexpr bool empty() requires @\libconcept{sized_range}@ || @\libconcept{forward_range}@ { + if constexpr (@\libconcept{sized_range}@) + return ranges::size(@\exposid{derived}@()) == 0; + else + return ranges::begin(@\exposid{derived}@()) == ranges::end(@\exposid{derived}@()); + } + constexpr bool empty() const requires @\libconcept{sized_range}@ || @\libconcept{forward_range}@ { + if constexpr (@\libconcept{sized_range}@) + return ranges::size(@\exposid{derived}@()) == 0; + else + return ranges::begin(@\exposid{derived}@()) == ranges::end(@\exposid{derived}@()); + } + + constexpr auto cbegin() { + return ranges::cbegin(@\exposid{derived}@()); + } + constexpr auto cbegin() const requires @\libconcept{range}@ { + return ranges::cbegin(@\exposid{derived}@()); + } + constexpr auto cend() { + return ranges::cend(@\exposid{derived}@()); } - constexpr bool empty() const requires @\libconcept{forward_range}@ { - return ranges::begin(@\exposid{derived}@()) == ranges::end(@\exposid{derived}@()); + constexpr auto cend() const requires @\libconcept{range}@ { + return ranges::cend(@\exposid{derived}@()); } constexpr explicit operator bool() @@ -1654,20 +1818,9 @@ @\libconcept{convertible_to}@ && !@\exposconcept{uses-nonqualification-pointer-conversion}@, decay_t>; - template - concept @\defexposconceptnc{pair-like}@ = // \expos - !is_reference_v && requires(T t) { - typename tuple_size::type; // ensures \tcode{tuple_size} is complete - requires @\libconcept{derived_from}@, integral_constant>; - typename tuple_element_t<0, remove_const_t>; - typename tuple_element_t<1, remove_const_t>; - { std::get<0>(t) } -> @\libconcept{convertible_to}@&>; - { std::get<1>(t) } -> @\libconcept{convertible_to}@&>; - }; - template concept @\defexposconceptnc{pair-like-convertible-from}@ = // \expos - !@\libconcept{range}@ && @\exposconcept{pair-like}@ && + !@\libconcept{range}@ && !is_reference_v && @\exposconcept{pair-like}@ && @\libconcept{constructible_from}@ && @\exposconcept{convertible-to-non-slicing}@> && @\libconcept{convertible_to}@>; @@ -1741,18 +1894,6 @@ template<@\libconcept{borrowed_range}@ R> subrange(R&&, @\placeholdernc{make-unsigned-like-t}@>) -> subrange, sentinel_t, subrange_kind::sized>; - - template - requires ((N == 0 && @\libconcept{copyable}@) || N == 1) - constexpr auto get(const subrange& r); - - template - requires (N < 2) - constexpr auto get(subrange&& r); -} - -namespace std { - using ranges::get; } \end{codeblock} @@ -1956,7 +2097,7 @@ \effects Equivalent to: \begin{codeblock} -if constexpr (bidirectional_iterator) { +if constexpr (@\libconcept{bidirectional_iterator}@) { if (n < 0) { ranges::advance(@\exposid{begin_}@, n); if constexpr (@\exposid{StoreSize}@) @@ -2050,6 +2191,38 @@ denote \tcode{dangling}. \end{itemize} +\rSec2[ranges.elementsof]{Class template \tcode{elements_of}} + +Specializations of \tcode{elements_of} encapsulate a range and +act as a tag in overload sets to disambiguate +when a range should be treated as a sequence +rather than a single value. + +\begin{example} +\begin{codeblock} +template +generator f(ranges::@\libconcept{input_range}@ auto&& r) { + if constexpr (YieldElements) + co_yield ranges::elements_of(r); // yield each element of \tcode{r} + else + co_yield r; // yield \tcode{r} as a single value +} +\end{codeblock} +\end{example} + +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{range}@ R, class Allocator = allocator> + struct elements_of { + [[no_unique_address]] R range; + [[no_unique_address]] Allocator allocator = Allocator(); + }; + + template> + elements_of(R&&, Allocator = Allocator()) -> elements_of; +} +\end{codeblock} + \rSec2[range.utility.conv]{Range conversions} \rSec3[range.utility.conv.general]{General} @@ -2101,13 +2274,13 @@ \pnum Let \exposid{container-inserter} be defined as follows: \begin{codeblock} -template -auto @\exposid{container-inserter}@(C& c) { // \expos +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()); -}; +} \end{codeblock} \rSec3[range.utility.conv.to]{\tcode{ranges::to}} @@ -2340,15 +2513,15 @@ \indexlibraryglobal{single_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{copy_constructible}@ T> + template<@\libconcept{move_constructible}@ T> requires is_object_v class single_view : public view_interface> { private: - @\exposidnc{copyable-box}@ @\exposidnc{value_}@; // \expos{} (see \ref{range.copy.wrap}) + @\exposidnc{movable-box}@ @\exposidnc{value_}@; // \expos{} (see \ref{range.move.wrap}) public: single_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit single_view(const T& t); + constexpr explicit single_view(const T& t) requires @\libconcept{copy_constructible}@; constexpr explicit single_view(T&& t); template requires @\libconcept{constructible_from}@ @@ -2370,7 +2543,7 @@ \indexlibraryctor{single_view}% \begin{itemdecl} -constexpr explicit single_view(const T& t); +constexpr explicit single_view(const T& t) requires @\libconcept{copy_constructible}@;; \end{itemdecl} \begin{itemdescr} @@ -2472,7 +2645,7 @@ \begin{example} \begin{codeblock} for (int i : views::iota(1, 10)) - cout << i << ' '; // prints: 1 2 3 4 5 6 7 8 9 + cout << i << ' '; // prints \tcode{1 2 3 4 5 6 7 8 9} \end{codeblock} \end{example} @@ -2694,7 +2867,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return iterator\{\exposid{value_}\};} +Equivalent to: \tcode{return \exposid{iterator}\{\exposid{value_}\};} \end{itemdescr} \indexlibrarymember{end}{iota_view}% @@ -2722,7 +2895,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return iterator\{bound_\};} +Equivalent to: \tcode{return \exposid{iterator}\{\exposid{bound_}\};} \end{itemdescr} \indexlibrarymember{size}{iota_view}% @@ -2766,7 +2939,8 @@ W @\exposid{value_}@ = W(); // \expos public: using iterator_concept = @\seebelow@; - using iterator_category = input_iterator_tag; // present only if \tcode{W} models \libconcept{incrementable} + using iterator_category = input_iterator_tag; // present only if \tcode{W} models \libconcept{incrementable} and + // \tcode{\placeholdernc{IOTA-DIFF-T}(W)} is an integral type using value_type = W; using difference_type = @\placeholdernc{IOTA-DIFF-T}@(W); @@ -3180,7 +3354,7 @@ \end{itemdescr} \begin{itemdecl} -friend constexpr iter_difference_t operator-(const @\exposid{iterator}@& x, const sentinel& y) +friend constexpr iter_difference_t operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) requires @\libconcept{sized_sentinel_for}@; \end{itemdecl} @@ -3201,925 +3375,3387 @@ Equivalent to: \tcode{return -(y - x);} \end{itemdescr} -\rSec2[range.istream]{Istream view} +\rSec2[range.repeat]{Repeat view} -\rSec3[range.istream.overview]{Overview} +\rSec3[range.repeat.overview]{Overview} \pnum -\tcode{basic_istream_view} models \libconcept{input_range} and -reads (using \tcode{operator>>}) successive elements -from its corresponding input stream. +\tcode{repeat_view} generates a sequence of elements +by repeatedly producing the same value. \pnum -The name \tcode{views::istream} denotes +\indexlibrarymember{repeat}{views}% +The name \tcode{views::repeat} denotes a customization point object\iref{customization.point.object}. -Given a type \tcode{T} and a subexpression \tcode{E} of type \tcode{U}, -if \tcode{U} models -\tcode{\libconcept{derived_from}>}, -then the expression \tcode{views::istream(E)} is expression-equivalent to -\tcode{basic_istream_view(E)}; -otherwise, \tcode{views::istream(E)} is ill-formed. +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. \pnum \begin{example} \begin{codeblock} -auto ints = istringstream{"0 1 2 3 4"}; -ranges::copy(ranges::istream_view(ints), ostream_iterator{cout, "-"}); -// prints \tcode{0-1-2-3-4-} +for (int i : views::repeat(17, 4)) + cout << i << ' '; +// prints \tcode{17 17 17 17} \end{codeblock} \end{example} -\rSec3[range.istream.view]{Class template \tcode{basic_istream_view}} +\rSec3[range.repeat.view]{Class template \tcode{repeat_view}} -\indexlibraryglobal{basic_istream_view}% \begin{codeblock} namespace std::ranges { - template - concept @\defexposconceptnc{stream-extractable}@ = // \expos - requires(basic_istream& is, Val& t) { - is >> t; - }; + template<@\libconcept{move_constructible}@ W, @\libconcept{semiregular}@ Bound = unreachable_sentinel_t> + requires (is_object_v && @\libconcept{same_as}@> && + (@\exposid{is-integer-like}@ || @\libconcept{same_as}@)) + class @\libglobal{repeat_view}@ : public view_interface> { + private: + // \ref{range.repeat.iterator}, class \tcode{repeat_view::\exposid{iterator}} + struct @\exposidnc{iterator}@; // \expos + + @\exposidnc{movable-box}@ @\exposid{value_}@ = W(); // \expos, see \ref{range.move.wrap} + Bound @\exposid{bound_}@ = Bound(); // \expos - template<@\libconcept{movable}@ Val, class CharT, class Traits = char_traits> - requires @\libconcept{default_initializable}@ && - @\exposconcept{stream-extractable}@ - class basic_istream_view : public view_interface> { public: - constexpr explicit basic_istream_view(basic_istream& stream); + repeat_view() requires @\libconcept{default_initializable}@ = default; - constexpr auto begin() { - *@\exposid{stream_}@ >> @\exposid{value_}@; - return @\exposid{iterator}@{*this}; - } + constexpr explicit repeat_view(const W& value, Bound bound = Bound()) + requires @\libconcept{copy_constructible}@; + constexpr explicit repeat_view(W&& value, Bound bound = Bound()); + template + requires @\libconcept{constructible_from}@ && + @\libconcept{constructible_from}@ + constexpr explicit repeat_view(piecewise_construct_t, + tuple value_args, tuple bound_args = tuple<>{}); - constexpr default_sentinel_t end() const noexcept; + constexpr @\exposid{iterator}@ begin() const; + constexpr @\exposid{iterator}@ end() const requires (!@\libconcept{same_as}@); + constexpr unreachable_sentinel_t end() const noexcept; - private: - struct @\exposidnc{iterator}@; // \expos - basic_istream* @\exposid{stream_}@; // \expos - Val @\exposid{value_}@ = Val(); // \expos + constexpr auto size() const requires (!@\libconcept{same_as}@); }; + + template + repeat_view(W, Bound) -> repeat_view; } \end{codeblock} -\indexlibraryctor{basic_istream_view}% +\indexlibraryctor{repeat_view}% \begin{itemdecl} -constexpr explicit basic_istream_view(basic_istream& stream); +constexpr explicit repeat_view(const W& value, Bound bound = Bound()) + requires @\libconcept{copy_constructible}@; \end{itemdecl} \begin{itemdescr} +\pnum +\expects +If \tcode{Bound} is not \tcode{unreachable_sentinel_t}, +$\tcode{bound} \ge 0$. + \pnum \effects -Initializes \exposid{stream_} with \tcode{addressof(stream)}. +Initializes \exposid{value_} with \tcode{value} and +\exposid{bound_} with \tcode{bound}. \end{itemdescr} -\indexlibrarymember{end}{basic_istream_view}% +\indexlibraryctor{repeat_view}% \begin{itemdecl} -constexpr default_sentinel_t end() const noexcept; +constexpr explicit repeat_view(W&& value, Bound bound = Bound()); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +If \tcode{Bound} is not \tcode{unreachable_sentinel_t}, $\tcode{bound} \ge 0$. + \pnum \effects -Equivalent to: \tcode{return default_sentinel;} +Initializes \exposid{value_} with \tcode{std::move(value)} and +\exposid{bound_} with \tcode{bound}. \end{itemdescr} -\rSec3[range.istream.iterator]{Class template \tcode{basic_istream_view::\exposid{iterator}}} - -\indexlibraryglobal{basic_istream_view::iterator}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{movable}@ Val, class CharT, class Traits> - requires @\libconcept{default_initializable}@ && - @\exposconcept{stream-extractable}@ - class basic_istream_view::@\exposid{iterator}@ { - public: - using iterator_concept = input_iterator_tag; - using difference_type = ptrdiff_t; - using value_type = Val; - - constexpr explicit @\exposid{iterator}@(basic_istream_view& parent) noexcept; - - @\exposid{iterator}@(const @\exposid{iterator}@&) = delete; - @\exposid{iterator}@(@\exposid{iterator}@&&) = default; - - @\exposid{iterator}@& operator=(const @\exposid{iterator}@&) = delete; - @\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default; - - @\exposid{iterator}@& operator++(); - void operator++(int); - - Val& operator*() const; - - friend bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); - - private: - basic_istream_view* @\exposid{parent_}@; // \expos - }; -} -\end{codeblock} - -\indexlibraryctor{basic_istream_view::iterator}% +\indexlibraryctor{repeat_view}% \begin{itemdecl} -constexpr explicit @\exposid{iterator}@(basic_istream_view& parent) noexcept; +template + requires @\libconcept{constructible_from}@ && + @\libconcept{constructible_from}@ +constexpr explicit repeat_view(piecewise_construct_t, + tuple value_args, tuple bound_args = tuple<>{}); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}. +Initializes \exposid{value_} with arguments of types \tcode{WArgs...} +obtained by forwarding the elements of \tcode{value_args} and +initializes \exposid{bound_} with arguments of types \tcode{BoundArgs...} +obtained by forwarding the elements of \tcode{bound_args}. +(Here, forwarding an element \tcode{x} of type \tcode{U} within a tuple object +means calling \tcode{std::forward(x)}.) \end{itemdescr} -\indexlibrarymember{operator++}{basic_istream_view::iterator}% +\indexlibrarymember{begin}{repeat_view}% \begin{itemdecl} -@\exposid{iterator}@& operator++(); +constexpr @\exposid{iterator}@ begin() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -*@\exposid{parent_}@->@\exposid{stream_}@ >> @\exposid{parent_}@->@\exposid{value_}@; -return *this; -\end{codeblock} +Equivalent to: \tcode{return \exposid{iterator}(addressof(*\exposid{value_}));} \end{itemdescr} -\indexlibrarymember{operator++}{basic_istream_view::iterator}% +\indexlibrarymember{end}{repeat_view}% \begin{itemdecl} -void operator++(int); +constexpr @\exposid{iterator}@ end() const requires (!@\libconcept{same_as}@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{++*this}. +Equivalent to: \tcode{return \exposid{iterator}(addressof(*\exposid{value_}), \exposid{bound_});} \end{itemdescr} -\indexlibrarymember{operator*}{basic_istream_view::iterator}% +\indexlibrarymember{end}{repeat_view}% \begin{itemdecl} -Val& operator*() const; +constexpr unreachable_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{parent_}->\exposid{value_};} +Equivalent to: \tcode{return unreachable_sentinel;} \end{itemdescr} -\indexlibrarymember{operator==}{basic_istream_view::iterator}% +\indexlibrarymember{size}{repeat_view}% \begin{itemdecl} -friend bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +constexpr auto size() const requires (!@\libconcept{same_as}@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !*x.\exposid{parent_}->\exposid{stream_};} +Equivalent to: \tcode{return \exposid{to-unsigned-like}(\exposid{bound_});} \end{itemdescr} -\rSec1[range.adaptors]{Range adaptors} +\rSec3[range.repeat.iterator]{Class \tcode{repeat_view::\exposid{iterator}}} -\rSec2[range.adaptors.general]{General} +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{move_constructible}@ W, @\libconcept{semiregular}@ Bound = unreachable_sentinel_t> + requires (is_object_v && @\libconcept{same_as}@> && + (@\exposid{is-integer-like}@ || @\libconcept{same_as}@)) + class repeat_view::@\exposid{iterator}@ { + private: + using @\exposidnc{index-type}@ = // \expos + conditional_t<@\libconcept{same_as}@, ptrdiff_t, Bound>; + const W* @\exposidnc{value_}@ = nullptr; // \expos + @\exposidnc{index-type}@ @\exposidnc{current_}@ = @\exposidnc{index-type}@(); // \expos -\pnum -Subclause \ref{range.adaptors} defines \term{range adaptors}, which are utilities that transform a -\libconcept{range} into a \libconcept{view} with custom behaviors. These -adaptors can be chained to create pipelines of range transformations that -evaluate lazily as the resulting view is iterated. + constexpr explicit @\exposid{iterator}@(const W* value, @\exposid{index-type}@ b = @\exposidnc{index-type}@()); // \expos -\pnum -Range adaptors are declared in namespace \tcode{std::ranges::views}. + public: + using iterator_concept = random_access_iterator_tag; + using iterator_category = random_access_iterator_tag; + using value_type = W; + using difference_type = conditional_t<@\exposid{is-signed-integer-like}@<@\exposid{index-type}@>, + @\exposid{index-type}@, + @\placeholdernc{IOTA-DIFF-T}@(@\exposid{index-type}@)>; -\pnum -The bitwise \logop{OR} operator is overloaded for the purpose of creating adaptor chain -pipelines. The adaptors also support function call syntax with equivalent -semantics. + @\exposid{iterator}@() = default; -\pnum -\begin{example} -\begin{codeblock} -vector ints{0,1,2,3,4,5}; -auto even = [](int i) { return 0 == i % 2; }; -auto square = [](int i) { return i * i; }; -for (int i : ints | views::filter(even) | views::transform(square)) { - cout << i << ' '; // prints: 0 4 16 + constexpr const W& operator*() const noexcept; + + constexpr @\exposid{iterator}@& operator++(); + constexpr @\exposid{iterator}@ operator++(int); + + constexpr @\exposid{iterator}@& operator--(); + constexpr @\exposid{iterator}@ operator--(int); + + constexpr @\exposid{iterator}@& operator+=(difference_type n); + constexpr @\exposid{iterator}@& operator-=(difference_type n); + constexpr const W& operator[](difference_type n) const noexcept; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); + + friend constexpr @\exposid{iterator}@ operator+(@\exposid{iterator}@ i, difference_type n); + friend constexpr @\exposid{iterator}@ operator+(difference_type n, @\exposid{iterator}@ i); + + friend constexpr @\exposid{iterator}@ operator-(@\exposid{iterator}@ i, difference_type n); + friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); + }; } -assert(ranges::equal(ints | views::filter(even), views::filter(ints, even))); \end{codeblock} -\end{example} -\rSec2[range.adaptor.object]{Range adaptor objects} +\indexlibraryctor{repeat_view::iterator}% +\begin{itemdecl} +constexpr explicit @\exposid{iterator}@(const W* value, @\exposid{index-type}@ b = @\exposid{index-type}@()); +\end{itemdecl} +\begin{itemdescr} \pnum -A \term{range adaptor closure object} is a unary function object that accepts -a \libconcept{range} argument. For -a range adaptor closure object \tcode{C} and an expression \tcode{R} such that -\tcode{decltype((R))} models \libconcept{range}, the following -expressions are equivalent: -\begin{codeblock} -C(R) -R | C -\end{codeblock} -Given an additional range adaptor closure object \tcode{D}, -the expression \tcode{C | D} produces another range adaptor -closure object \tcode{E}. -\tcode{E} is a perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} -with the following properties: -\begin{itemize} -\item -Its target object is an object \tcode{d} of type \tcode{decay_t} -direct-non-list-initialized with \tcode{D}. -\item -It has one bound argument entity, -an object \tcode{c} of type \tcode{decay_t} -direct-non-list-initialized with \tcode{C}. -\item -Its call pattern is \tcode{d(c(arg))}, -where \tcode{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 of \tcode{E} are all well-formed. +\expects +If \tcode{Bound} is not \tcode{unreachable_sentinel_t}, $\tcode{b} \ge 0$. \pnum -Given an object \tcode{t} of type \tcode{T}, where -\begin{itemize} -\item -\tcode{t} is a unary function object that accepts a \libconcept{range} argument, -\item -\tcode{T} models \tcode{\libconcept{derived_from}>}, -\item -\tcode{T} has no other base classes of type \tcode{range_adaptor_closure} for any other type \tcode{U}, and -\item -\tcode{T} does not model \libconcept{range} -\end{itemize} -then the implementation ensures -that \tcode{t} is a range adaptor closure object. +\effects +Initializes \exposid{value_} with \tcode{value} and +\exposid{current_} with \tcode{b}. +\end{itemdescr} -\pnum -The template parameter \tcode{D} for \tcode{range_adaptor_closure} -may be an incomplete type. -If an expression of type \cv{} \tcode{D} -is used 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. +\indexlibrarymember{operator*}{repeat_view::iterator}% +\begin{itemdecl} +constexpr const W& operator*() const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -If an expression of type \cv{} \tcode{U} -is used as an operand to the \tcode{|} operator, -where \tcode{U} has a base class of type \tcode{range_adaptor_closure} -for some type \tcode{T} other than \tcode{U}, the behavior is undefined. +\effects +Equivalent to: \tcode{return *\exposid{value_};} +\end{itemdescr} -\pnum -The behavior of a program -that adds a specialization for \tcode{range_adaptor_closure} is undefined. +\indexlibrarymember{operator++}{repeat_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} +\begin{itemdescr} \pnum -A \term{range adaptor object} is a -customization point object\iref{customization.point.object} -that accepts a \libconcept{viewable_range} as its first argument and returns a -\libconcept{view}. +\effects +Equivalent to: +\begin{codeblock} +++@\exposid{current_}@; +return *this; +\end{codeblock} +\end{itemdescr} -\pnum -If a range adaptor object accepts only one argument, -then it is a range adaptor closure object. +\indexlibrarymember{operator++}{repeat_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int); +\end{itemdecl} +\begin{itemdescr} \pnum -If a range adaptor object \tcode{adaptor} accepts more than one argument, -then let \tcode{range} be an expression -such that \tcode{decltype((range))} models \libconcept{viewable_range}, -let \tcode{args...} be arguments -such that \tcode{adaptor(range, args...)} is a well-formed expression -as specified in the rest of subclause~\ref{range.adaptors}, and -let \tcode{BoundArgs} be a pack -that denotes \tcode{decay_t...}. -The expression \tcode{adaptor(args...)} produces a range adaptor closure object \tcode{f} -that is a perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} with the following properties: -\begin{itemize} -\item -Its target object is a copy of \tcode{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(r, bound_args...)}, -where \tcode{r} 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 initialization of the bound argument entities of the result, -as specified above, are all well-formed. +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} -\rSec2[range.copy.wrap]{Copyable wrapper} +\indexlibrarymember{operator--}{repeat_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--(); +\end{itemdecl} +\begin{itemdescr} \pnum -Many types in this subclause are specified in terms of -an exposition-only class template \exposid{copyable-box}. -\tcode{\exposid{copyable-box}} behaves exactly like \tcode{optional} -with the following differences: -\begin{itemize} -\item \tcode{\exposid{copyable-box}} constrains -its type parameter \tcode{T} with -\tcode{\libconcept{copy_constructible} \&\& is_object_v}. +\expects +If \tcode{Bound} is not \tcode{unreachable_sentinel_t}, +$\exposid{current_} > 0$. -\item The default -constructor of \tcode{\exposid{copyable-box}} is equivalent to: +\pnum +\effects +Equivalent to: \begin{codeblock} -constexpr @\exposid{copyable-box}@() noexcept(is_nothrow_default_constructible_v) - requires @\libconcept{default_initializable}@ - : @\exposid{copyable-box}@{in_place} {} +--@\exposid{current_}@; +return *this; \end{codeblock} +\end{itemdescr} -\item If \tcode{\libconcept{copyable}} is not -modeled, the copy assignment operator is equivalent to: +\indexlibrarymember{operator--}{repeat_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator--(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -constexpr @\exposid{copyable-box}@& operator=(const @\exposid{copyable-box}@& that) - noexcept(is_nothrow_copy_constructible_v) { - if (this != addressof(that)) { - if (that) emplace(*that); - else reset(); - } - return *this; -} +auto tmp = *this; +--*this; +return tmp; \end{codeblock} +\end{itemdescr} -\item If \tcode{\libconcept{movable}} is not modeled, -the move assignment operator is equivalent to: +\indexlibrarymember{operator+=}{repeat_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator+=(difference_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +If \tcode{Bound} is not \tcode{unreachable_sentinel_t}, +$\exposid{current_} + \tcode{n} \ge 0$. + +\pnum +\effects +Equivalent to: \begin{codeblock} -constexpr @\exposid{copyable-box}@& operator=(@\exposid{copyable-box}@&& that) - noexcept(is_nothrow_move_constructible_v) { - if (this != addressof(that)) { - if (that) emplace(std::move(*that)); - else reset(); - } - return *this; -} +@\exposid{current_}@ += n; +return *this; \end{codeblock} -\end{itemize} +\end{itemdescr} -\pnum -\recommended -\tcode{\exposid{copyable-box}} should store only a \tcode{T} -if either \tcode{T} models \libconcept{copyable} or -\tcode{is_nothrow_move_constructible_v \&\& is_nothrow_copy_constructible_v} -is \tcode{true}. +\indexlibrarymember{operator-=}{repeat_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator-=(difference_type n); +\end{itemdecl} -\rSec2[range.nonprop.cache]{Non-propagating cache} +\begin{itemdescr} +\pnum +\expects +If \tcode{Bound} is not \tcode{unreachable_sentinel_t}, +$\exposid{current_} - \tcode{n} \ge 0$. \pnum -Some types in subclause \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: -\begin{itemize} -\item -\tcode{\exposid{non-propagating-cache}} constrains its type parameter \tcode{T} -with \tcode{is_object_v}. -\item -The copy constructor is equivalent to: +\effects +Equivalent to: \begin{codeblock} -constexpr @\exposid{non-propagating-cache}@(const @\exposid{non-propagating-cache}@&) noexcept {} +@\exposid{current_}@ -= n; +return *this; \end{codeblock} -\item -The move constructor is equivalent to: -\begin{codeblock} -constexpr @\exposid{non-propagating-cache}@(@\exposid{non-propagating-cache}@&& other) noexcept { - other.reset(); -} -\end{codeblock} -\item -The copy assignment operator is equivalent to: -\begin{codeblock} -constexpr @\exposid{non-propagating-cache}@& operator=(const @\exposid{non-propagating-cache}@& other) noexcept { - if (addressof(other) != this) - reset(); - return *this; -} -\end{codeblock} -\item -The move assignment operator is equivalent to: -\begin{codeblock} -constexpr @\exposid{non-propagating-cache}@& operator=(@\exposid{non-propagating-cache}@&& other) noexcept { - reset(); - other.reset(); - return *this; -} -\end{codeblock} -\item -\tcode{\exposid{non-propagating-cache}} has an additional member function template -specified as follows: +\end{itemdescr} + +\indexlibrarymember{operator[]}{repeat_view::iterator}% \begin{itemdecl} -template - constexpr T& @\exposid{emplace-deref}@(const I& i); // \expos +constexpr const W& operator[](difference_type n) const noexcept; \end{itemdecl} \begin{itemdescr} -% Indenting the \item markers is necessary to avoid check errors complaining -% about missing pnum. - \mandates -The declaration \tcode{T t(*i);} is well-formed -for some invented variable \tcode{t}. -\begin{note} -If \tcode{*i} is a prvalue of type \cv{} \tcode{T}, -there is no requirement that it is movable\iref{dcl.init.general}. -\end{note} - - \effects -Calls \tcode{reset()}. -Then direct-non-list-initializes the contained value with \tcode{*i}. - - \ensures -\tcode{*this} contains a value. - - \returns -A reference to the new contained value. - - \throws -Any exception thrown by the initialization of the contained value. - - \remarks -If an exception is thrown during the initialization of \tcode{T}, -\tcode{*this} does not contain a value, and -the previous value (if any) has been destroyed. -\end{itemdescr} -\end{itemize} - \pnum -\begin{note} -\exposid{non-propagating-cache} enables an input view -to temporarily cache values as it is iterated over. -\end{note} - -\rSec2[range.all]{All view} - -\rSec3[range.all.general]{General} +\effects +Equivalent to: \tcode{return *(*this + n);} +\end{itemdescr} -\pnum -\indexlibrarymember{all}{views}% -\tcode{views::all} returns a \libconcept{view} that includes all elements of -its \libconcept{range} argument. +\indexlibrarymember{operator==}{repeat_view::iterator}% +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +\end{itemdecl} +\begin{itemdescr} \pnum -The name \tcode{views::all} denotes a -range adaptor object\iref{range.adaptor.object}. -Given a subexpression \tcode{E}, the expression -\tcode{views::all(E)} is expression-equivalent to: -\begin{itemize} -\item \tcode{\placeholdernc{decay-copy}(E)} if the decayed type of \tcode{E} -models \libconcept{view}. - -\item Otherwise, \tcode{ref_view\{E\}} if that expression is well-formed. - -\item Otherwise, \tcode{owning_view\{E\}}. -\end{itemize} +\effects +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};}. +\end{itemdescr} -\rSec3[range.ref.view]{Class template \tcode{ref_view}} +\indexlibrarymember{operator<=>}{repeat_view::iterator}% +\begin{itemdecl} +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +\end{itemdecl} +\begin{itemdescr} \pnum -\tcode{ref_view} is a \libconcept{view} of the elements of some other \libconcept{range}. -\indexlibraryglobal{ref_view}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{range}@ R> - requires is_object_v - class ref_view : public view_interface> { - private: - R* @\exposid{r_}@; // \expos - public: - template<@\exposconcept{different-from}@ T> - requires @\seebelow@ - constexpr ref_view(T&& t); - - constexpr R& base() const { return *@\exposid{r_}@; } - - constexpr iterator_t begin() const { return ranges::begin(*@\exposid{r_}@); } - constexpr sentinel_t end() const { return ranges::end(*@\exposid{r_}@); } - - constexpr bool empty() const - requires requires { ranges::empty(*@\exposid{r_}@); } - { return ranges::empty(*@\exposid{r_}@); } - - constexpr auto size() const requires @\libconcept{sized_range}@ - { return ranges::size(*@\exposid{r_}@); } - - constexpr auto data() const requires @\libconcept{contiguous_range}@ - { return ranges::data(*@\exposid{r_}@); } - }; - - template - ref_view(R&) -> ref_view; -} -\end{codeblock} +\effects +Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};}. +\end{itemdescr} -\indexlibraryglobal{ref_view}% +\indexlibrarymember{operator+}{repeat_view::iterator}% \begin{itemdecl} -template<@\exposconcept{different-from}@ T> - requires @\seebelow@ -constexpr ref_view(T&& t); +friend constexpr @\exposid{iterator}@ operator+(@\exposid{iterator}@ i, difference_type n); +friend constexpr @\exposid{iterator}@ operator+(difference_type n, @\exposid{iterator}@ i); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{r_} with -\tcode{addressof(static_cast(std::forward(t)))}. - -\pnum -\remarks -Let \tcode{\placeholder{FUN}} denote the exposition-only functions -\begin{codeblock} -void @\placeholder{FUN}@(R&); -void @\placeholder{FUN}@(R&&) = delete; -\end{codeblock} -The expression in the \grammarterm{requires-clause} is equivalent to: +Equivalent to: \begin{codeblock} -@\libconcept{convertible_to}@ && requires { @\placeholder{FUN}@(declval()); } +i += n; +return i; \end{codeblock} \end{itemdescr} -\rSec3[range.owning.view]{Class template \tcode{owning_view}} +\indexlibrarymember{operator-}{repeat_view::iterator}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator-(@\exposid{iterator}@ i, difference_type n); +\end{itemdecl} +\begin{itemdescr} \pnum -\tcode{owning_view} is a move-only view -of the elements of some other \libconcept{range}. +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{range}@ R> - requires @\libconcept{movable}@ && (!@\exposid{is-initializer-list}@) // see \ref{range.refinements} - class owning_view : public view_interface> { - private: - R @\exposid{r_}@ = R(); // \expos - public: - owning_view() requires @\libconcept{default_initializable}@ = default; - constexpr owning_view(R&& t); - - owning_view(owning_view&&) = default; - owning_view& operator=(owning_view&&) = default; - - constexpr R& base() & noexcept { return @\exposid{r_}@; } - constexpr const R& base() const & noexcept { return @\exposid{r_}@; } - constexpr R&& base() && noexcept { return std::move(@\exposid{r_}@); } - constexpr const R&& base() const && noexcept { return std::move(@\exposid{r_}@); } - - constexpr iterator_t begin() { return ranges::begin(@\exposid{r_}@); } - constexpr sentinel_t end() { return ranges::end(@\exposid{r_}@); } - - constexpr auto begin() const requires @\libconcept{range}@ - { return ranges::begin(@\exposid{r_}@); } - constexpr auto end() const requires @\libconcept{range}@ - { return ranges::end(@\exposid{r_}@); } - - constexpr bool empty() requires requires { ranges::empty(@\exposid{r_}@); } - { return ranges::empty(@\exposid{r_}@); } - constexpr bool empty() const requires requires { ranges::empty(@\exposid{r_}@); } - { return ranges::empty(@\exposid{r_}@); } - - constexpr auto size() requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{r_}@); } - constexpr auto size() const requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{r_}@); } - - constexpr auto data() requires @\libconcept{contiguous_range}@ - { return ranges::data(@\exposid{r_}@); } - constexpr auto data() const requires @\libconcept{contiguous_range}@ - { return ranges::data(@\exposid{r_}@); } - }; -} +i -= n; +return i; \end{codeblock} +\end{itemdescr} +\indexlibrarymember{operator-}{repeat_view::iterator}% \begin{itemdecl} -constexpr owning_view(R&& t); +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{r_} with \tcode{std::move(t)}. +Equivalent to: +\begin{codeblock} +return static_cast(x.@\exposid{current_}@) - static_cast(y.@\exposid{current_}@); +\end{codeblock} \end{itemdescr} -\rSec2[range.filter]{Filter view} +\rSec2[range.istream]{Istream view} -\rSec3[range.filter.overview]{Overview} +\rSec3[range.istream.overview]{Overview} \pnum -\tcode{filter_view} presents a \libconcept{view} of the elements -of an underlying sequence that satisfy a predicate. +\tcode{basic_istream_view} models \libconcept{input_range} and +reads (using \tcode{operator>>}) successive elements +from its corresponding input stream. \pnum -\indexlibrarymember{filter}{views}% -The name \tcode{views::filter} denotes a -range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{P}, -the expression \tcode{views::filter(E, P)} is expression-equivalent to -\tcode{filter_view(E, P)}. +The name \tcode{views::istream} denotes +a customization point object\iref{customization.point.object}. +Given a type \tcode{T} and a subexpression \tcode{E} of type \tcode{U}, +if \tcode{U} models +\tcode{\libconcept{derived_from}>}, +then the expression \tcode{views::istream(E)} is expression-equivalent to +\tcode{basic_istream_view(E)}; +otherwise, \tcode{views::istream(E)} is ill-formed. \pnum \begin{example} \begin{codeblock} -vector is{ 0, 1, 2, 3, 4, 5, 6 }; -auto evens = views::filter(is, [](int i) { return 0 == i % 2; }); -for (int i : evens) - cout << i << ' '; // prints: 0 2 4 6 +auto ints = istringstream{"0 1 2 3 4"}; +ranges::copy(views::istream(ints), ostream_iterator{cout, "-"}); +// prints \tcode{0-1-2-3-4-} \end{codeblock} \end{example} -\rSec3[range.filter.view]{Class template \tcode{filter_view}} +\rSec3[range.istream.view]{Class template \tcode{basic_istream_view}} -\indexlibraryglobal{filter_view}% -\indexlibrarymember{base}{filter_view}% -\indexlibrarymember{end}{filter_view}% +\indexlibraryglobal{basic_istream_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> - requires @\libconcept{view}@ && is_object_v - class filter_view : public view_interface> { - private: - V @\exposid{base_}@ = V(); // \expos - @\exposidnc{copyable-box}@ @\exposid{pred_}@; // \expos - - // \ref{range.filter.iterator}, class \tcode{filter_view::\exposid{iterator}} - class @\exposid{iterator}@; // \expos - - // \ref{range.filter.sentinel}, class \tcode{filter_view::\exposid{sentinel}} - class @\exposid{sentinel}@; // \expos + template + concept @\defexposconceptnc{stream-extractable}@ = // \expos + requires(basic_istream& is, Val& t) { + is >> t; + }; + template<@\libconcept{movable}@ Val, class CharT, class Traits = char_traits> + requires @\libconcept{default_initializable}@ && + @\exposconcept{stream-extractable}@ + class basic_istream_view : public view_interface> { public: - filter_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr filter_view(V base, Pred pred); + constexpr explicit basic_istream_view(basic_istream& stream); - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + constexpr auto begin() { + *@\exposid{stream_}@ >> @\exposid{value_}@; + return @\exposid{iterator}@{*this}; + } - constexpr const Pred& pred() const; + constexpr default_sentinel_t end() const noexcept; - constexpr @\exposid{iterator}@ begin(); - constexpr auto end() { - if constexpr (@\libconcept{common_range}@) - return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; - else - return @\exposid{sentinel}@{*this}; - } + private: + // \ref{range.istream.iterator}, class \tcode{basic_istream_view::\exposid{iterator}} + struct @\exposidnc{iterator}@; // \expos + basic_istream* @\exposid{stream_}@; // \expos + Val @\exposid{value_}@ = Val(); // \expos }; - - template - filter_view(R&&, Pred) -> filter_view, Pred>; } \end{codeblock} -\indexlibraryctor{filter_view}% +\indexlibraryctor{basic_istream_view}% \begin{itemdecl} -constexpr filter_view(V base, Pred pred); +constexpr explicit basic_istream_view(basic_istream& stream); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)} and initializes -\exposid{pred_} with \tcode{std::move(pred)}. +Initializes \exposid{stream_} with \tcode{addressof(stream)}. \end{itemdescr} -\indexlibrarymember{pred}{filter_view}% +\indexlibrarymember{end}{basic_istream_view}% \begin{itemdecl} -constexpr const Pred& pred() const; +constexpr default_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *\exposid{pred_};} -\end{itemdescr} - -\indexlibrarymember{begin}{filter_view}% -\begin{itemdecl} -constexpr @\exposid{iterator}@ begin(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{pred_.has_value()} is \tcode{true}. - -\pnum -\returns -\tcode{\{*this, ranges::find_if(\exposid{base_}, ref(*\exposid{pred_}))\}}. - -\pnum -\remarks -In order to provide the amortized constant time complexity required by -the \libconcept{range} concept -when \tcode{filter_view} models \libconcept{forward_range}, -this function caches the result within the -\tcode{filter_view} for use on subsequent calls. +Equivalent to: \tcode{return default_sentinel;} \end{itemdescr} -\rSec3[range.filter.iterator]{Class \tcode{filter_view::\exposid{iterator}}} +\rSec3[range.istream.iterator]{Class \tcode{basic_istream_view::\exposid{iterator}}} -\indexlibrarymember{iterator}{filter_view}% +\indexlibraryglobal{basic_istream_view::iterator}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> - requires @\libconcept{view}@ && is_object_v - class filter_view::@\exposid{iterator}@ { - private: - iterator_t @\exposid{current_}@ = iterator_t(); // \expos - filter_view* @\exposid{parent_}@ = nullptr; // \expos - + template<@\libconcept{movable}@ Val, class CharT, class Traits> + requires @\libconcept{default_initializable}@ && + @\exposconcept{stream-extractable}@ + class basic_istream_view::@\exposid{iterator}@ { public: - using iterator_concept = @\seebelownc@; - using iterator_category = @\seebelownc@; // not always present - using value_type = range_value_t; - using difference_type = range_difference_t; + using iterator_concept = input_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = Val; - @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; - constexpr @\exposid{iterator}@(filter_view& parent, iterator_t current); + constexpr explicit @\exposid{iterator}@(basic_istream_view& parent) noexcept; - constexpr const iterator_t& base() const & noexcept; - constexpr iterator_t base() &&; - constexpr range_reference_t operator*() const; - constexpr iterator_t operator->() const - requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; + @\exposid{iterator}@(const @\exposid{iterator}@&) = delete; + @\exposid{iterator}@(@\exposid{iterator}@&&) = default; - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@; + @\exposid{iterator}@& operator=(const @\exposid{iterator}@&) = delete; + @\exposid{iterator}@& operator=(@\exposid{iterator}@&&) = default; - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; + @\exposid{iterator}@& operator++(); + void operator++(int); - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; + Val& operator*() const; - friend constexpr range_rvalue_reference_t iter_move(const @\exposid{iterator}@& i) - noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); + friend bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); - 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}@>; + private: + basic_istream_view* @\exposid{parent_}@; // \expos }; } \end{codeblock} -\pnum -Modification of the element a \tcode{filter_view::\exposid{iterator}} denotes is -permitted, but results in undefined behavior if the resulting value does not -satisfy the filter predicate. - -\pnum -\tcode{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, if \tcode{V} models \libconcept{forward_range}, then -\tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. - -\item Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. -\end{itemize} - -\pnum -The member \grammarterm{typedef-name} \tcode{iterator_category} is defined -if and only if \tcode{V} 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{bi\-directional_iterator_tag}. - -\item Otherwise, if \tcode{C} models -\tcode{\libconcept{derived_from}}, -then \tcode{iterator_category} denotes \tcode{forward_iterator_tag}. - -\item Otherwise, \tcode{iterator_category} denotes \tcode{C}. -\end{itemize} - -\indexlibraryctor{filter_view::iterator}% +\indexlibraryctor{basic_istream_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@(filter_view& parent, iterator_t current); +constexpr explicit @\exposid{iterator}@(basic_istream_view& parent) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(current)} and -\exposid{parent_} with \tcode{addressof(parent)}. +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} -\indexlibrarymember{base}{filter_view::iterator}% +\indexlibrarymember{operator++}{basic_istream_view::iterator}% \begin{itemdecl} -constexpr const iterator_t& base() const & noexcept; +@\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{current_};} +Equivalent to: +\begin{codeblock} +*@\exposid{parent_}@->@\exposid{stream_}@ >> @\exposid{parent_}@->@\exposid{value_}@; +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{filter_view::iterator}% +\indexlibrarymember{operator++}{basic_istream_view::iterator}% \begin{itemdecl} -constexpr iterator_t base() &&; +void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return std::move(current_);} +Equivalent to \tcode{++*this}. \end{itemdescr} -\indexlibrarymember{operator*}{filter_view::iterator}% +\indexlibrarymember{operator*}{basic_istream_view::iterator}% \begin{itemdecl} -constexpr range_reference_t operator*() const; +Val& operator*() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *\exposid{current_};} +Equivalent to: \tcode{return \exposid{parent_}->\exposid{value_};} \end{itemdescr} -\indexlibrarymember{operator->}{filter_view::iterator}% +\indexlibrarymember{operator==}{basic_istream_view::iterator}% \begin{itemdecl} -constexpr iterator_t operator->() const - requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; +friend bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{current_};} +Equivalent to: \tcode{return !*x.\exposid{parent_}->\exposid{stream_};} \end{itemdescr} -\indexlibrarymember{operator++}{filter_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); -\end{itemdecl} +\rSec1[range.adaptors]{Range adaptors} -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{current_}@ = ranges::find_if(std::move(++@\exposid{current_}@), ranges::end(@\exposid{parent_}@->@\exposid{base_}@), - ref(*@\exposid{parent_}@->@\exposid{pred_}@)); -return *this; -\end{codeblock} -\end{itemdescr} +\rSec2[range.adaptors.general]{General} -\indexlibrarymember{operator++}{filter_view::iterator}% -\begin{itemdecl} -constexpr void operator++(int); -\end{itemdecl} +\pnum +Subclause \ref{range.adaptors} defines \term{range adaptors}, which are utilities that transform a +\libconcept{range} into a \libconcept{view} with custom behaviors. These +adaptors can be chained to create pipelines of range transformations that +evaluate lazily as the resulting view is iterated. -\begin{itemdescr} \pnum -\effects -Equivalent to \tcode{++*this}. -\end{itemdescr} +Range adaptors are declared in namespace \tcode{std::ranges::views}. -\indexlibrarymember{operator++}{filter_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@; -\end{itemdecl} +\pnum +The bitwise \logop{or} operator is overloaded for the purpose of creating adaptor chain +pipelines. The adaptors also support function call syntax with equivalent +semantics. -\begin{itemdescr} \pnum -\effects -Equivalent to: +\begin{example} \begin{codeblock} -auto tmp = *this; -++*this; -return tmp; +vector ints{0,1,2,3,4,5}; +auto even = [](int i) { return 0 == i % 2; }; +auto square = [](int i) { return i * i; }; +for (int i : ints | views::filter(even) | views::transform(square)) { + cout << i << ' '; // prints \tcode{0 4 16} +} +assert(ranges::equal(ints | views::filter(even), views::filter(ints, even))); \end{codeblock} -\end{itemdescr} +\end{example} -\indexlibrarymember{operator--}{filter_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; -\end{itemdecl} +\rSec2[range.adaptor.object]{Range adaptor objects} -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -do - --@\exposid{current_}@; +A \term{range adaptor closure object} is a unary function object that accepts +a \libconcept{range} argument. For +a range adaptor closure object \tcode{C} and an expression \tcode{R} such that +\tcode{decltype((R))} models \libconcept{range}, the following +expressions are equivalent: +\begin{codeblock} +C(R) +R | C +\end{codeblock} +Given an additional range adaptor closure object \tcode{D}, +the expression \tcode{C | D} produces another range adaptor +closure object \tcode{E}. +\tcode{E} is a perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} +with the following properties: +\begin{itemize} +\item +Its target object is an object \tcode{d} of type \tcode{decay_t} +direct-non-list-initialized with \tcode{D}. +\item +It has one bound argument entity, +an object \tcode{c} of type \tcode{decay_t} +direct-non-list-initialized with \tcode{C}. +\item +Its call pattern is \tcode{d(c(arg))}, +where \tcode{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 of \tcode{E} are all well-formed. + +\pnum +Given an object \tcode{t} of type \tcode{T}, where +\begin{itemize} +\item +\tcode{t} is a unary function object that accepts a \libconcept{range} argument, +\item +\tcode{T} models \tcode{\libconcept{derived_from}>}, +\item +\tcode{T} has no other base classes of type \tcode{range_adaptor_closure} for any other type \tcode{U}, and +\item +\tcode{T} does not model \libconcept{range} +\end{itemize} +then the implementation ensures +that \tcode{t} is a range adaptor closure object. + +\pnum +The template parameter \tcode{D} for \tcode{range_adaptor_closure} +may be an incomplete type. +If an expression of type \cv{} \tcode{D} +is used 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 +If an expression of type \cv{} \tcode{U} +is used as an operand to the \tcode{|} operator, +where \tcode{U} has a base class of type \tcode{range_adaptor_closure} +for some type \tcode{T} other than \tcode{U}, the behavior is undefined. + +\pnum +The behavior of a program +that adds a specialization for \tcode{range_adaptor_closure} is undefined. + +\pnum +A \term{range adaptor object} is a +customization point object\iref{customization.point.object} +that accepts a \libconcept{viewable_range} as its first argument and returns a +\libconcept{view}. + +\pnum +If a range adaptor object accepts only one argument, +then it is a range adaptor closure object. + +\pnum +If a range adaptor object \tcode{adaptor} accepts more than one argument, +then let \tcode{range} be an expression +such that \tcode{decltype((range))} models \libconcept{viewable_range}, +let \tcode{args...} be arguments +such that \tcode{adaptor(range, args...)} is a well-formed expression +as specified in the rest of subclause~\ref{range.adaptors}, and +let \tcode{BoundArgs} be a pack +that denotes \tcode{decay_t...}. +The expression \tcode{adaptor(args...)} produces a range adaptor closure object \tcode{f} +that is a perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} with the following properties: +\begin{itemize} +\item +Its target object is a copy of \tcode{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(r, bound_args...)}, +where \tcode{r} 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 initialization of the bound argument entities of the result, +as specified above, are all well-formed. + +\rSec2[range.move.wrap]{Movable wrapper} + +\pnum +Many types in this subclause are specified in terms of +an exposition-only class template \exposid{movable-box}. +\tcode{\exposid{movable-box}} behaves exactly like \tcode{optional} +with the following differences: +\begin{itemize} +\item \tcode{\exposid{movable-box}} constrains +its type parameter \tcode{T} with +\tcode{\libconcept{move_constructible} \&\& is_object_v}. + +\item The default +constructor of \tcode{\exposid{movable-box}} is equivalent to: +\begin{codeblock} +constexpr @\exposid{movable-box}@() noexcept(is_nothrow_default_constructible_v) + requires @\libconcept{default_initializable}@ + : @\exposid{movable-box}@{in_place} {} +\end{codeblock} + +\item If \tcode{\libconcept{copyable}} is not +modeled, the copy assignment operator is equivalent to: +\begin{codeblock} +constexpr @\exposid{movable-box}@& operator=(const @\exposid{movable-box}@& that) + noexcept(is_nothrow_copy_constructible_v) + requires @\libconcept{copy_constructible}@ { + if (this != addressof(that)) { + if (that) emplace(*that); + else reset(); + } + return *this; +} +\end{codeblock} + +\item If \tcode{\libconcept{movable}} is not modeled, +the move assignment operator is equivalent to: +\begin{codeblock} +constexpr @\exposid{movable-box}@& operator=(@\exposid{movable-box}@&& that) + noexcept(is_nothrow_move_constructible_v) { + if (this != addressof(that)) { + if (that) emplace(std::move(*that)); + else reset(); + } + return *this; +} +\end{codeblock} +\end{itemize} + +\pnum +\recommended +\begin{itemize} +\item +If \tcode{\libconcept{copy_constructible}} is \tcode{true}, +\tcode{\exposid{movable-box}} should store only a \tcode{T} +if either \tcode{T} models \libconcept{copyable}, or +\tcode{is_nothrow_move_constructible_v \&\& is_nothrow_copy_constructible_v} +is \tcode{true}. +\item +Otherwise, \tcode{\exposid{movable-box}} should store only a \tcode{T} +if either \tcode{T} models \libconcept{movable} or +\tcode{is_nothrow_move_constructible_v} is \tcode{true}. +\end{itemize} + +\rSec2[range.nonprop.cache]{Non-propagating cache} + +\pnum +Some types in subclause \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: +\begin{itemize} +\item +\tcode{\exposid{non-propagating-cache}} constrains its type parameter \tcode{T} +with \tcode{is_object_v}. +\item +The copy constructor is equivalent to: +\begin{codeblock} +constexpr @\exposid{non-propagating-cache}@(const @\exposid{non-propagating-cache}@&) noexcept {} +\end{codeblock} +\item +The move constructor is equivalent to: +\begin{codeblock} +constexpr @\exposid{non-propagating-cache}@(@\exposid{non-propagating-cache}@&& other) noexcept { + other.reset(); +} +\end{codeblock} +\item +The copy assignment operator is equivalent to: +\begin{codeblock} +constexpr @\exposid{non-propagating-cache}@& operator=(const @\exposid{non-propagating-cache}@& other) noexcept { + if (addressof(other) != this) + reset(); + return *this; +} +\end{codeblock} +\item +The move assignment operator is equivalent to: +\begin{codeblock} +constexpr @\exposid{non-propagating-cache}@& operator=(@\exposid{non-propagating-cache}@&& other) noexcept { + reset(); + other.reset(); + return *this; +} +\end{codeblock} +\item +\tcode{\exposid{non-propagating-cache}} has an additional member function template +specified as follows: +\begin{itemdecl} +template + constexpr T& @\exposid{emplace-deref}@(const I& i); // \expos +\end{itemdecl} + +\begin{itemdescr} +% Indenting the \item markers is necessary to avoid check errors complaining +% about missing pnum. + \mandates +The declaration \tcode{T t(*i);} is well-formed +for some invented variable \tcode{t}. +\begin{note} +If \tcode{*i} is a prvalue of type \cv{} \tcode{T}, +there is no requirement that it is movable\iref{dcl.init.general}. +\end{note} + + \effects +Calls \tcode{reset()}. +Then direct-non-list-initializes the contained value with \tcode{*i}. + + \ensures +\tcode{*this} contains a value. + + \returns +A reference to the new contained value. + + \throws +Any exception thrown by the initialization of the contained value. + + \remarks +If an exception is thrown during the initialization of \tcode{T}, +\tcode{*this} does not contain a value, and +the previous value (if any) has been destroyed. +\end{itemdescr} +\end{itemize} + +\pnum +\begin{note} +\exposid{non-propagating-cache} enables an input view +to temporarily cache values as it is iterated over. +\end{note} + +\rSec2[range.adaptor.tuple]{Range adaptor helpers} + +\begin{codeblock} +namespace std::ranges { + template + constexpr auto @\exposid{tuple-transform}@(F&& f, Tuple&& t) { // \expos + return apply([&](Ts&&... elements) { + return tuple...>(invoke(f, std::forward(elements))...); + }, std::forward(t)); + } + + template + constexpr void @\exposid{tuple-for-each}@(F&& f, Tuple&& t) { // \expos + apply([&](Ts&&... elements) { + (invoke(f, std::forward(elements)), ...); + }, std::forward(t)); + } +} +\end{codeblock} + +\rSec2[range.all]{All view} + +\rSec3[range.all.general]{General} + +\pnum +\indexlibrarymember{all}{views}% +\tcode{views::all} returns a \libconcept{view} that includes all elements of +its \libconcept{range} argument. + +\pnum +The name \tcode{views::all} denotes a +range adaptor object\iref{range.adaptor.object}. +Given a subexpression \tcode{E}, the expression +\tcode{views::all(E)} is expression-equivalent to: +\begin{itemize} +\item \tcode{\placeholdernc{decay-copy}(E)} if the decayed type of \tcode{E} +models \libconcept{view}. + +\item Otherwise, \tcode{ref_view\{E\}} if that expression is well-formed. + +\item Otherwise, \tcode{owning_view\{E\}}. +\end{itemize} + +\rSec3[range.ref.view]{Class template \tcode{ref_view}} + +\pnum +\tcode{ref_view} is a \libconcept{view} of the elements of some other \libconcept{range}. +\indexlibraryglobal{ref_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{range}@ R> + requires is_object_v + class ref_view : public view_interface> { + private: + R* @\exposid{r_}@; // \expos + public: + template<@\exposconcept{different-from}@ T> + requires @\seebelow@ + constexpr ref_view(T&& t); + + constexpr R& base() const { return *@\exposid{r_}@; } + + constexpr iterator_t begin() const { return ranges::begin(*@\exposid{r_}@); } + constexpr sentinel_t end() const { return ranges::end(*@\exposid{r_}@); } + + constexpr bool empty() const + requires requires { ranges::empty(*@\exposid{r_}@); } + { return ranges::empty(*@\exposid{r_}@); } + + constexpr auto size() const requires @\libconcept{sized_range}@ + { return ranges::size(*@\exposid{r_}@); } + + constexpr auto data() const requires @\libconcept{contiguous_range}@ + { return ranges::data(*@\exposid{r_}@); } + }; + + template + ref_view(R&) -> ref_view; +} +\end{codeblock} + +\indexlibraryctor{ref_view}% +\begin{itemdecl} +template<@\exposconcept{different-from}@ T> + requires @\seebelow@ +constexpr ref_view(T&& t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{r_} with +\tcode{addressof(static_cast(std::forward(t)))}. + +\pnum +\remarks +Let \tcode{\placeholder{FUN}} denote the exposition-only functions +\begin{codeblock} +void @\placeholder{FUN}@(R&); +void @\placeholder{FUN}@(R&&) = delete; +\end{codeblock} +The expression in the \grammarterm{requires-clause} is equivalent to: +\begin{codeblock} +@\libconcept{convertible_to}@ && requires { @\placeholder{FUN}@(declval()); } +\end{codeblock} +\end{itemdescr} + +\rSec3[range.owning.view]{Class template \tcode{owning_view}} + +\pnum +\tcode{owning_view} is a move-only view +of the elements of some other \libconcept{range}. +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{range}@ R> + requires @\libconcept{movable}@ && (!@\exposid{is-initializer-list}@) // see \ref{range.refinements} + class owning_view : public view_interface> { + private: + R @\exposid{r_}@ = R(); // \expos + public: + owning_view() requires @\libconcept{default_initializable}@ = default; + constexpr owning_view(R&& t); + + owning_view(owning_view&&) = default; + owning_view& operator=(owning_view&&) = default; + + constexpr R& base() & noexcept { return @\exposid{r_}@; } + constexpr const R& base() const & noexcept { return @\exposid{r_}@; } + constexpr R&& base() && noexcept { return std::move(@\exposid{r_}@); } + constexpr const R&& base() const && noexcept { return std::move(@\exposid{r_}@); } + + constexpr iterator_t begin() { return ranges::begin(@\exposid{r_}@); } + constexpr sentinel_t end() { return ranges::end(@\exposid{r_}@); } + + constexpr auto begin() const requires @\libconcept{range}@ + { return ranges::begin(@\exposid{r_}@); } + constexpr auto end() const requires @\libconcept{range}@ + { return ranges::end(@\exposid{r_}@); } + + constexpr bool empty() requires requires { ranges::empty(@\exposid{r_}@); } + { return ranges::empty(@\exposid{r_}@); } + constexpr bool empty() const requires requires { ranges::empty(@\exposid{r_}@); } + { return ranges::empty(@\exposid{r_}@); } + + constexpr auto size() requires @\libconcept{sized_range}@ + { return ranges::size(@\exposid{r_}@); } + constexpr auto size() const requires @\libconcept{sized_range}@ + { return ranges::size(@\exposid{r_}@); } + + constexpr auto data() requires @\libconcept{contiguous_range}@ + { return ranges::data(@\exposid{r_}@); } + constexpr auto data() const requires @\libconcept{contiguous_range}@ + { return ranges::data(@\exposid{r_}@); } + }; +} +\end{codeblock} + +\begin{itemdecl} +constexpr owning_view(R&& t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{r_} with \tcode{std::move(t)}. +\end{itemdescr} + +\rSec2[range.as.rvalue]{As rvalue view} + +\rSec3[range.as.rvalue.overview]{Overview} + +\pnum +\tcode{as_rvalue_view} presents a \libconcept{view} of an underlying sequence +with the same behavior as the underlying sequence +except that its elements are rvalues. +Some generic algorithms can be called with a \tcode{as_rvalue_view} +to replace copying with moving. + +\pnum +\indexlibrarymember{as_rvalue}{views}% +The name \tcode{views::as_rvalue} 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::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}. +\item +Otherwise, \tcode{as_rvalue_view(E)}. +\end{itemize} + +\pnum +\begin{example} +\begin{codeblock} +vector words = {"the", "quick", "brown", "fox", "ate", "a", "pterodactyl"}; +vector new_words; +ranges::copy(words | views::as_rvalue, back_inserter(new_words)); + // moves each string from \tcode{words} into \tcode{new_words} +\end{codeblock} +\end{example} + +\rSec3[range.as.rvalue.view]{Class template \tcode{as_rvalue_view}} + +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\libconcept{input_range}@ + class @\libglobal{as_rvalue_view}@ : public view_interface> { + V @\exposid{base_}@ = V(); // \expos + + public: + as_rvalue_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit as_rvalue_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 move_iterator(ranges::begin(@\exposid{base_}@)); } + constexpr auto begin() const requires @\libconcept{range}@ + { return move_iterator(ranges::begin(@\exposid{base_}@)); } + + constexpr auto end() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{common_range}@) { + return move_iterator(ranges::end(@\exposid{base_}@)); + } else { + return move_sentinel(ranges::end(@\exposid{base_}@)); + } + } + constexpr auto end() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{common_range}@) { + return move_iterator(ranges::end(@\exposid{base_}@)); + } else { + return move_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_}@); } + }; + + template + as_rvalue_view(R&&) -> as_rvalue_view>; +} +\end{codeblock} + +\indexlibraryctor{as_rvalue_view}% +\begin{itemdecl} +constexpr explicit as_rvalue_view(V base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\rSec2[range.filter]{Filter view} + +\rSec3[range.filter.overview]{Overview} + +\pnum +\tcode{filter_view} presents a \libconcept{view} of the elements +of an underlying sequence that satisfy a predicate. + +\pnum +\indexlibrarymember{filter}{views}% +The name \tcode{views::filter} denotes a +range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{P}, +the expression \tcode{views::filter(E, P)} is expression-equivalent to +\tcode{filter_view(E, P)}. + +\pnum +\begin{example} +\begin{codeblock} +vector is{ 0, 1, 2, 3, 4, 5, 6 }; +auto evens = views::filter(is, [](int i) { return 0 == i % 2; }); +for (int i : evens) + cout << i << ' '; // prints \tcode{0 2 4 6} +\end{codeblock} +\end{example} + +\rSec3[range.filter.view]{Class template \tcode{filter_view}} + +\indexlibraryglobal{filter_view}% +\indexlibrarymember{base}{filter_view}% +\indexlibrarymember{end}{filter_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> + requires @\libconcept{view}@ && is_object_v + class filter_view : public view_interface> { + private: + V @\exposid{base_}@ = V(); // \expos + @\exposidnc{movable-box}@ @\exposid{pred_}@; // \expos + + // \ref{range.filter.iterator}, class \tcode{filter_view::\exposid{iterator}} + class @\exposid{iterator}@; // \expos + + // \ref{range.filter.sentinel}, class \tcode{filter_view::\exposid{sentinel}} + class @\exposid{sentinel}@; // \expos + + public: + filter_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr filter_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() { + if constexpr (@\libconcept{common_range}@) + return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; + else + return @\exposid{sentinel}@{*this}; + } + }; + + template + filter_view(R&&, Pred) -> filter_view, Pred>; +} +\end{codeblock} + +\indexlibraryctor{filter_view}% +\begin{itemdecl} +constexpr filter_view(V base, Pred pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and initializes +\exposid{pred_} with \tcode{std::move(pred)}. +\end{itemdescr} + +\indexlibrarymember{pred}{filter_view}% +\begin{itemdecl} +constexpr const Pred& pred() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return *\exposid{pred_};} +\end{itemdescr} + +\indexlibrarymember{begin}{filter_view}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ begin(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. + +\pnum +\returns +\tcode{\{*this, ranges::find_if(\exposid{base_}, ref(*\exposid{pred_}))\}}. + +\pnum +\remarks +In order to provide the amortized constant time complexity required by +the \libconcept{range} concept +when \tcode{filter_view} models \libconcept{forward_range}, +this function caches the result within the +\tcode{filter_view} for use on subsequent calls. +\end{itemdescr} + +\rSec3[range.filter.iterator]{Class \tcode{filter_view::\exposid{iterator}}} + +\indexlibrarymember{iterator}{filter_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> + requires @\libconcept{view}@ && is_object_v + class filter_view::@\exposid{iterator}@ { + private: + iterator_t @\exposid{current_}@ = iterator_t(); // \expos + filter_view* @\exposid{parent_}@ = nullptr; // \expos + + public: + using iterator_concept = @\seebelownc@; + using iterator_category = @\seebelownc@; // not always present + using value_type = range_value_t; + using difference_type = range_difference_t; + + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; + constexpr @\exposid{iterator}@(filter_view& parent, iterator_t current); + + constexpr const iterator_t& base() const & noexcept; + constexpr iterator_t base() &&; + constexpr range_reference_t operator*() const; + constexpr iterator_t operator->() const + requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; + + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@; + + 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) + requires @\libconcept{equality_comparable}@>; + + friend constexpr range_rvalue_reference_t 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 +Modification of the element a \tcode{filter_view::\exposid{iterator}} denotes is +permitted, but results in undefined behavior if the resulting value does not +satisfy the filter predicate. + +\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, if \tcode{V} models \libconcept{forward_range}, then +\tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. + +\item Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\pnum +The member \grammarterm{typedef-name} \tcode{iterator_category} is defined +if and only if \tcode{V} 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{bi\-directional_iterator_tag}. + +\item Otherwise, if \tcode{C} models +\tcode{\libconcept{derived_from}}, +then \tcode{iterator_category} denotes \tcode{forward_iterator_tag}. + +\item Otherwise, \tcode{iterator_category} denotes \tcode{C}. +\end{itemize} + +\indexlibraryctor{filter_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(filter_view& parent, iterator_t current); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(current)} and +\exposid{parent_} with \tcode{addressof(parent)}. +\end{itemdescr} + +\indexlibrarymember{base}{filter_view::iterator}% +\begin{itemdecl} +constexpr const iterator_t& base() const & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{base}{filter_view::iterator}% +\begin{itemdecl} +constexpr iterator_t base() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return std::move(\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{operator*}{filter_view::iterator}% +\begin{itemdecl} +constexpr range_reference_t operator*() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return *\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator->}{filter_view::iterator}% +\begin{itemdecl} +constexpr iterator_t operator->() const + requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator++}{filter_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ = ranges::find_if(std::move(++@\exposid{current_}@), ranges::end(@\exposid{parent_}@->@\exposid{base_}@), + ref(*@\exposid{parent_}@->@\exposid{pred_}@)); +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{filter_view::iterator}% +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{++*this}. +\end{itemdescr} + +\indexlibrarymember{operator++}{filter_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{filter_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +do + --@\exposid{current_}@; while (!invoke(*@\exposid{parent_}@->@\exposid{pred_}@, *@\exposid{current_}@)); return *this; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator--}{filter_view::iterator}% +\indexlibrarymember{operator--}{filter_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +--*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator==}{filter_view::iterator}% +\begin{itemdecl} +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{return x.\exposid{current_} == y.\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{iter_move}{filter_view::iterator}% +\begin{itemdecl} +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: \tcode{return ranges::iter_move(i.\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{iter_swap}{filter_view::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.filter.sentinel]{Class \tcode{filter_view::\exposid{sentinel}}} + +\indexlibrarymember{sentinel}{filter_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> + requires @\libconcept{view}@ && is_object_v + class filter_view::@\exposid{sentinel}@ { + private: + sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos + + public: + @\exposid{sentinel}@() = default; + constexpr explicit @\exposid{sentinel}@(filter_view& parent); + + constexpr sentinel_t base() const; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + }; +} +\end{codeblock} + +\indexlibraryctor{filter_view::sentinel}% +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(filter_view& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. +\end{itemdescr} + +\indexlibrarymember{base}{filter_view::sentinel}% +\begin{itemdecl} +constexpr sentinel_t base() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{end_};} +\end{itemdescr} + +\indexlibrarymember{operator==}{filter_view::sentinel}% +\begin{itemdecl} +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} + +\rSec2[range.transform]{Transform view} + +\rSec3[range.transform.overview]{Overview} + +\pnum +\tcode{transform_view} presents +a \libconcept{view} of an underlying sequence after +applying a transformation function to each element. + +\pnum +\indexlibrarymember{transform}{views}% +The name \tcode{views::transform} denotes a +range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{F}, the expression +\tcode{views::transform(E, F)} is expression-equivalent to +\tcode{transform_view(E, F)}. + +\pnum +\begin{example} +\begin{codeblock} +vector is{ 0, 1, 2, 3, 4 }; +auto squares = views::transform(is, [](int i) { return i * i; }); +for (int i : squares) + cout << i << ' '; // prints \tcode{0 1 4 9 16} +\end{codeblock} +\end{example} + +\rSec3[range.transform.view]{Class template \tcode{transform_view}} + +\indexlibraryglobal{transform_view}% +\indexlibrarymember{base}{transform_view}% +\indexlibrarymember{size}{transform_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{move_constructible}@ F> + requires @\libconcept{view}@ && is_object_v && + @\libconcept{regular_invocable}@> && + @\exposconcept{can-reference}@>> + class transform_view : public view_interface> { + private: + // \ref{range.transform.iterator}, class template \tcode{transform_view::\exposid{iterator}} + template struct @\exposid{iterator}@; // \expos + + // \ref{range.transform.sentinel}, class template \tcode{transform_view::\exposid{sentinel}} + template struct @\exposid{sentinel}@; // \expos + + V @\exposid{base_}@ = V(); // \expos + @\placeholdernc{movable-box}@ @\exposid{fun_}@; // \expos + + public: + transform_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr 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 @\exposid{iterator}@ begin(); + constexpr @\exposid{iterator}@ begin() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@>; + + constexpr @\exposid{sentinel}@ end(); + constexpr @\exposid{iterator}@ end() requires @\libconcept{common_range}@; + constexpr @\exposid{sentinel}@ end() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@>; + constexpr @\exposid{iterator}@ end() const + requires @\libconcept{common_range}@ && + @\libconcept{regular_invocable}@>; + + 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 + transform_view(R&&, F) -> transform_view, F>; +} +\end{codeblock} + +\indexlibraryctor{transform_view}% +\begin{itemdecl} +constexpr transform_view(V base, F fun); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{fun_} with \tcode{std::move(fun)}. +\end{itemdescr} + +\indexlibrarymember{begin}{transform_view}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ begin(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{begin}{transform_view}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ begin() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{end}{transform_view}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@ end(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{end}{transform_view}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ end() requires @\libconcept{common_range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{end}{transform_view}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@ end() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{end}{transform_view}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ end() const + requires @\libconcept{common_range}@ && + @\libconcept{regular_invocable}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; +\end{codeblock} +\end{itemdescr} + +\rSec3[range.transform.iterator]{Class template \tcode{transform_view::\exposid{iterator}}} + +\indexlibraryglobal{transform_view::iterator}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{move_constructible}@ F> + requires @\libconcept{view}@ && is_object_v && + @\libconcept{regular_invocable}@> && + @\exposconcept{can-reference}@>> + template + class transform_view::@\exposid{iterator}@ { + private: + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + iterator_t<@\exposidnc{Base}@> @\exposid{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos + @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + + public: + using iterator_concept = @\seebelownc@; + using iterator_category = @\seebelownc@; // not always present + using value_type = + remove_cvref_t&, range_reference_t<@\exposid{Base}@>>>; + using difference_type = range_difference_t<@\exposid{Base}@>; + + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, 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 + noexcept(noexcept(invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *@\exposid{current_}@))) { + return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *@\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 invoke(*@\exposid{parent_}@->@\exposid{fun_}@, @\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+(@\exposid{iterator}@ i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + friend constexpr @\exposid{iterator}@ operator+(difference_type n, @\exposid{iterator}@ i) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + + friend constexpr @\exposid{iterator}@ operator-(@\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}@>>; + }; +} +\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} + +\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: +Let \tcode{C} denote the type +\tcode{iterator_traits>::iterator_category}. +\begin{itemize} +\item +If \tcode{is_lvalue_reference_v\&, range_reference_t<\linebreak\exposid{Base}>>>} +is \tcode{true}, then +\begin{itemize} +\item +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} + +\item +Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\indexlibrarymember{iterator}{transform_view::iterator} +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(current)} and +\exposid{parent_} with \tcode{addressof(parent)}. +\end{itemdescr} + +\indexlibraryctor{transform_view::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{parent_} with \tcode{i.\exposid{parent_}}. +\end{itemdescr} + +\indexlibrarymember{base}{transform_view::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}{transform_view::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++}{transform_view::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++}{transform_view::iterator}% +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{++\exposid{current_}}. +\end{itemdescr} + +\indexlibrarymember{operator++}{transform_view::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 tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{transform_view::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--}{transform_view::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 tmp = *this; +--*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator+=}{transform_view::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-=}{transform_view::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==}{transform_view::iterator}% +\begin{itemdecl} +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{return x.\exposid{current_} == y.\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator<}{transform_view::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>}{transform_view::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<=}{transform_view::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>=}{transform_view::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<=>}{transform_view::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+}{transform_view::iterator}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator+(@\exposid{iterator}@ i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(difference_type n, @\exposid{iterator}@ i) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}\{*i.\exposid{parent_}, i.\exposid{current_} + n\};} +\end{itemdescr} + +\indexlibrarymember{operator-}{transform_view::iterator}% +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator-(@\exposid{iterator}@ i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{iterator}\{*i.\exposid{parent_}, i.\exposid{current_} - n\};} +\end{itemdescr} + +\indexlibrarymember{operator-}{transform_view::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.transform.sentinel]{Class template \tcode{transform_view::\exposid{sentinel}}} + +\indexlibraryglobal{transform_view::sentinel}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{move_constructible}@ F> + requires @\libconcept{view}@ && is_object_v && + @\libconcept{regular_invocable}@> && + @\exposconcept{can-reference}@>> + template + class transform_view::@\exposid{sentinel}@ { + private: + using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos + 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}@ i) + 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}@& y, const @\exposid{iterator}@& x); + }; +} +\end{codeblock} + +\indexlibraryctor{transform_view::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{transform_view::sentinel}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. +\end{itemdescr} + +\indexlibrarymember{base}{transform_view::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==}{transform_view::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-}{transform_view::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-}{transform_view::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}@& y, const @\exposid{iterator}@& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return y.\exposid{end_} - x.\exposid{current_};} +\end{itemdescr} + +\rSec2[range.take]{Take view} + +\rSec3[range.take.overview]{Overview} + +\pnum +\tcode{take_view} produces a \libconcept{view} of the first $N$ elements +from another \libconcept{view}, or all the elements if the adapted +\libconcept{view} contains fewer than $N$. + +\pnum +\indexlibrarymember{take}{views}% +The name \tcode{views::take} denotes a +range adaptor object\iref{range.adaptor.object}. +Let \tcode{E} and \tcode{F} be expressions, +let \tcode{T} be \tcode{remove_cvref_t}, and +let \tcode{D} be \tcode{range_difference_t}. +If \tcode{decltype((F))} does not model +\tcode{\libconcept{convertible_to}}, +\tcode{views::take(E, F)} is ill-formed. +Otherwise, the expression \tcode{views::take(E, F)} +is expression-equivalent to: + +\begin{itemize} +\item +If \tcode{T} is a specialization +of \tcode{ranges::empty_view}\iref{range.empty.view}, +then \tcode{((void)F, \placeholdernc{decay-copy}(E))}, +except that the evaluations of \tcode{E} and \tcode{F} +are indeterminately sequenced. + +\item +Otherwise, if \tcode{T} models +\libconcept{random_access_range} and \libconcept{sized_range} +and is a specialization of +\tcode{span}\iref{views.span}, +\tcode{basic_string_view}\iref{string.view}, or +\tcode{ranges::subrange}\iref{range.subrange}, +then +\tcode{U(ranges::begin(E), +ranges::be\-gin(E) + std::min(ranges::distance(E), F))}, +except that \tcode{E} is evaluated only once, +where \tcode{U} is a type determined as follows: + +\begin{itemize} +\item if \tcode{T} is a specialization of \tcode{span}, +then \tcode{U} is \tcode{span}; +\item otherwise, if \tcode{T} is a specialization of \tcode{basic_string_view}, +then \tcode{U} is \tcode{T}; +\item otherwise, \tcode{T} is a specialization of \tcode{ranges::subrange}, and +\tcode{U} is \tcode{ranges::subrange>}; +\end{itemize} + +\item +otherwise, if \tcode{T} is +a specialization of \tcode{ranges::iota_view}\iref{range.iota.view} +that models \libconcept{random_access_range} and \libconcept{sized_range}, +then +\tcode{ranges::iota_view(*ranges::begin(E), +*(ranges::begin(E) + std::\linebreak{}min(ranges::distance(E), F)))}, +except that \tcode{E} is evaluated only once. + +\item +Otherwise, if \tcode{T} is +a specialization of \tcode{ranges::repeat_view}\iref{range.repeat.view}: +\begin{itemize} +\item +if \tcode{T} models \libconcept{sized_range}, +then +\begin{codeblock} +views::repeat(*E.@\exposid{value_}@, std::min(ranges::distance(E), F)) +\end{codeblock} +except that \tcode{E} is evaluated only once; +\item +otherwise, \tcode{views::repeat(*E.\exposid{value_}, static_cast(F))}. +\end{itemize} + +\item +Otherwise, \tcode{ranges::take_view(E, F)}. +\end{itemize} + +\pnum +\begin{example} +\begin{codeblock} +vector is{0,1,2,3,4,5,6,7,8,9}; +for (int i : is | views::take(5)) + cout << i << ' '; // prints \tcode{0 1 2 3 4} +\end{codeblock} +\end{example} + +\rSec3[range.take.view]{Class template \tcode{take_view}} + +\indexlibraryglobal{take_view}% +\indexlibrarymember{base}{take_view}% +\indexlibrarymember{begin}{take_view}% +\indexlibrarymember{end}{take_view}% +\indexlibrarymember{size}{take_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + class take_view : public view_interface> { + private: + V @\exposid{base_}@ = V(); // \expos + range_difference_t @\exposid{count_}@ = 0; // \expos + + // \ref{range.take.sentinel}, class template \tcode{take_view::\exposid{sentinel}} + template class @\exposid{sentinel}@; // \expos + + public: + take_view() requires @\libconcept{default_initializable}@ = default; + constexpr take_view(V base, range_difference_t count); + + 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}@) { + if constexpr (@\libconcept{sized_range}@) { + if constexpr (@\libconcept{random_access_range}@) { + return ranges::begin(@\exposid{base_}@); + } else { + auto sz = range_difference_t(size()); + return counted_iterator(ranges::begin(@\exposid{base_}@), sz); + } + } else { + return counted_iterator(ranges::begin(@\exposid{base_}@), @\exposid{count_}@); + } + } + + constexpr auto begin() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{sized_range}@) { + if constexpr (@\libconcept{random_access_range}@) { + return ranges::begin(@\exposid{base_}@); + } else { + auto sz = range_difference_t(size()); + return counted_iterator(ranges::begin(@\exposid{base_}@), sz); + } + } else { + return counted_iterator(ranges::begin(@\exposid{base_}@), @\exposid{count_}@); + } + } + + constexpr auto end() requires (!@\exposconcept{simple-view}@) { + if constexpr (@\libconcept{sized_range}@) { + if constexpr (@\libconcept{random_access_range}@) + return ranges::begin(@\exposid{base_}@) + range_difference_t(size()); + else + return default_sentinel; + } else { + return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; + } + } + + constexpr auto end() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{sized_range}@) { + if constexpr (@\libconcept{random_access_range}@) + return ranges::begin(@\exposid{base_}@) + range_difference_t(size()); + else + return default_sentinel; + } else { + return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; + } + } + + constexpr auto size() requires @\libconcept{sized_range}@ { + auto n = ranges::size(@\exposid{base_}@); + return ranges::min(n, static_cast(@\exposid{count_}@)); + } + + constexpr auto size() const requires @\libconcept{sized_range}@ { + auto n = ranges::size(@\exposid{base_}@); + return ranges::min(n, static_cast(@\exposid{count_}@)); + } + }; + + template + take_view(R&&, range_difference_t) + -> take_view>; +} +\end{codeblock} + +\indexlibraryctor{take_view}% +\begin{itemdecl} +constexpr take_view(V base, range_difference_t count); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{count_} with \tcode{count}. +\end{itemdescr} + +\rSec3[range.take.sentinel]{Class template \tcode{take_view::\exposid{sentinel}}} + +\indexlibraryglobal{take_view::sentinel}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + template + class take_view::@\exposid{sentinel}@ { + private: + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + template + using @\exposid{CI}@ = counted_iterator>>; // \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}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + + constexpr sentinel_t<@\exposid{Base}@> base() const; + + friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); + + template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); + }; +} +\end{codeblock} + +\indexlibraryctor{take_view::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{take_view::sentinel}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(s.\exposid{end_})}. +\end{itemdescr} + +\indexlibrarymember{base}{take_view::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==}{take_view::sentinel}% +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); + +template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return y.count() == 0 || y.base() == x.\exposid{end_};} +\end{itemdescr} + +\rSec2[range.take.while]{Take while view} + +\rSec3[range.take.while.overview]{Overview} + +\pnum +Given a unary predicate \tcode{pred} and a \libconcept{view} \tcode{r}, +\tcode{take_while_view} produces a \libconcept{view} +of the range \range{ranges::be\-gin(r)}{ranges::find_if_not(r, pred)}. + +\indexlibraryglobal{take_while}% +\pnum +\indexlibrarymember{take_while}{views}% +The name \tcode{views::take_while} denotes +a range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::take_while(E, F)} +is expression-equivalent to \tcode{take_while_view(E, F)}. + +\pnum +\begin{example} +\begin{codeblock} +auto input = istringstream{"0 1 2 3 4 5 6 7 8 9"}; +auto small = [](const auto x) noexcept { return x < 5; }; +auto small_ints = views::istream(input) | views::take_while(small); +for (const auto i : small_ints) { + cout << i << ' '; // prints \tcode{0 1 2 3 4} +} +auto i = 0; +input >> i; +cout << i; // prints \tcode{6} +\end{codeblock} +\end{example} + +\rSec3[range.take.while.view]{Class template \tcode{take_while_view}} + +\indexlibraryglobal{take_while_view}% +\indexlibrarymember{base}{take_while_view}% +\indexlibrarymember{begin}{take_while_view}% +\indexlibrarymember{end}{take_while_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V, class Pred> + requires @\libconcept{input_range}@ && is_object_v && + @\libconcept{indirect_unary_predicate}@> + class take_while_view : public view_interface> { + // \ref{range.take.while.sentinel}, class template \tcode{take_while_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos + + V @\exposid{base_}@ = V(); // \expos + @\exposidnc{movable-box}@ @\exposid{pred_}@; // \expos + + public: + take_while_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr take_while_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 auto begin() requires (!@\exposconcept{simple-view}@) + { return ranges::begin(@\exposid{base_}@); } + + constexpr auto begin() const + requires @\libconcept{range}@ && + @\libconcept{indirect_unary_predicate}@> + { return ranges::begin(@\exposid{base_}@); } + + constexpr auto end() requires (!@\exposconcept{simple-view}@) + { return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@), addressof(*@\exposid{pred_}@)); } + + constexpr auto end() const + requires @\libconcept{range}@ && + @\libconcept{indirect_unary_predicate}@> + { return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@), addressof(*@\exposid{pred_}@)); } + }; + + template + take_while_view(R&&, Pred) -> take_while_view, Pred>; +} +\end{codeblock} + +\indexlibraryctor{take_while_view}% +\begin{itemdecl} +constexpr take_while_view(V base, Pred pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{pred_} with \tcode{std::move(pred)}. +\end{itemdescr} + +\indexlibrarymember{pred}{take_while_view}% +\begin{itemdecl} +constexpr const Pred& pred() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return *\exposid{pred_};} +\end{itemdescr} + +\rSec3[range.take.while.sentinel]{Class template \tcode{take_while_view::\exposid{sentinel}}} + +\indexlibraryglobal{take_while_view::sentinel}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V, class Pred> + requires @\libconcept{input_range}@ && is_object_v && + @\libconcept{indirect_unary_predicate}@> + template + class take_while_view::@\exposidnc{sentinel}@ { + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + + sentinel_t<@\exposidnc{Base}@> @\exposid{end_}@ = sentinel_t<@\exposidnc{Base}@>(); // \expos + const Pred* @\exposid{pred_}@ = nullptr; // \expos + + public: + @\exposid{sentinel}@() = default; + constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end, const Pred* pred); + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + + constexpr sentinel_t<@\exposid{Base}@> base() const { return @\exposid{end_}@; } + + friend constexpr bool operator==(const iterator_t<@\exposid{Base}@>& x, const @\exposid{sentinel}@& y); + + template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr bool operator==(const iterator_t<@\exposid{maybe-const}@>& x, + const @\exposid{sentinel}@& y); + }; +} +\end{codeblock} + +\indexlibraryctor{take_while_view::sentinel}% +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end, const Pred* pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{end} and \exposid{pred_} with \tcode{pred}. +\end{itemdescr} + +\indexlibraryctor{take_while_view::sentinel}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(s.\exposid{end_})} and +\exposid{pred_} with \tcode{s.\exposid{pred_}}. +\end{itemdescr} + +\indexlibrarymember{operator==}{take_while_view::sentinel}% +\begin{itemdecl} +friend constexpr bool operator==(const iterator_t<@\exposid{Base}@>& x, const @\exposid{sentinel}@& y); + +template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> +friend constexpr bool operator==(const iterator_t<@\exposid{maybe-const}@>& x, + const @\exposid{sentinel}@& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return y.\exposid{end_} == x || !invoke(*y.\exposid{pred_}, *x);} +\end{itemdescr} + +\rSec2[range.drop]{Drop view} + +\rSec3[range.drop.overview]{Overview} + +\pnum +\tcode{drop_view} produces a \libconcept{view} +excluding the first $N$ elements from another \libconcept{view}, or +an empty range if the adapted \libconcept{view} contains fewer than $N$ elements. + +\pnum +\indexlibrarymember{drop}{views}% +The name \tcode{views::drop} denotes +a range adaptor object\iref{range.adaptor.object}. +Let \tcode{E} and \tcode{F} be expressions, +let \tcode{T} be \tcode{remove_cvref_t}, and +let \tcode{D} be \tcode{range_difference_t}. +If \tcode{decltype((F))} does not model +\tcode{\libconcept{convertible_to}}, +\tcode{views::drop(E, F)} is ill-formed. +Otherwise, the expression \tcode{views::drop(E, F)} +is expression-equivalent to: + +\begin{itemize} +\item +If \tcode{T} is a specialization of +\tcode{ranges::empty_view}\iref{range.empty.view}, +then \tcode{((void)F, \placeholdernc{decay-copy}(E))}, +except that the evaluations of \tcode{E} and \tcode{F} +are indeterminately sequenced. + +\item +Otherwise, if \tcode{T} models +\libconcept{random_access_range} and \libconcept{sized_range} +and is +\begin{itemize} +\item a specialization of \tcode{span}\iref{views.span}, +\item a specialization of \tcode{basic_string_view}\iref{string.view}, +\item a specialization of \tcode{ranges::iota_view}\iref{range.iota.view}, or +\item a specialization of \tcode{ranges::subrange}\iref{range.subrange} +where \tcode{T::\exposid{StoreSize}} is \tcode{false}, +\end{itemize} +then \tcode{U(ranges::begin(E) + std::min(ranges::distance(E), F), ranges::end(E))}, +except that \tcode{E} is evaluated only once, +where \tcode{U} is \tcode{span} +if \tcode{T} is a specialization of \tcode{span} and \tcode{T} otherwise. + +\item +Otherwise, +if \tcode{T} is +a specialization of \tcode{ranges::subrange}\iref{range.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), +\exposid{to-unsigned-like}(ranges::distance(E) - +std::min(ranges::distance(E), F)))}, +except that \tcode{E} and \tcode{F} are each evaluated only once. + +\item +Otherwise, if \tcode{T} is +a specialization of \tcode{ranges::repeat_view}\iref{range.repeat.view}: +\begin{itemize} +\item +if \tcode{T} models \libconcept{sized_range}, +then +\begin{codeblock} +views::repeat(*E.@\exposid{value_}@, ranges::distance(E) - std::min(ranges::distance(E), F)) +\end{codeblock} +except that \tcode{E} is evaluated only once; +\item +otherwise, \tcode{((void)F, \placeholdernc{decay-copy}(E))}, +except that the evaluations of \tcode{E} and \tcode{F} are indeterminately sequenced. +\end{itemize} + +\item +Otherwise, \tcode{ranges::drop_view(E, F)}. +\end{itemize} + +\pnum +\begin{example} +\begin{codeblock} +auto ints = views::iota(0) | views::take(10); +for (auto i : ints | views::drop(5)) { + cout << i << ' '; // prints \tcode{5 6 7 8 9} +} +\end{codeblock} +\end{example} + +\rSec3[range.drop.view]{Class template \tcode{drop_view}} + +\indexlibraryglobal{drop_view}% +\indexlibrarymember{base}{drop_view}% +\indexlibrarymember{end}{drop_view}% +\indexlibrarymember{size}{drop_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + class drop_view : public view_interface> { + public: + drop_view() requires @\libconcept{default_initializable}@ = default; + constexpr drop_view(V base, range_difference_t count); + + 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}@ && + @\libconcept{random_access_range}@ && @\libconcept{sized_range}@)); + constexpr auto begin() const + requires @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; + + constexpr auto end() requires (!@\exposconcept{simple-view}@) + { return ranges::end(@\exposid{base_}@); } + + constexpr auto end() const requires @\libconcept{range}@ + { return ranges::end(@\exposid{base_}@); } + + constexpr auto size() requires @\libconcept{sized_range}@ { + const auto s = ranges::size(@\exposid{base_}@); + const auto c = static_cast(@\exposid{count_}@); + return s < c ? 0 : s - c; + } + + constexpr auto size() const requires @\libconcept{sized_range}@ { + const auto s = ranges::size(@\exposid{base_}@); + const auto c = static_cast(@\exposid{count_}@); + return s < c ? 0 : s - c; + } + + private: + V @\exposid{base_}@ = V(); // \expos + range_difference_t @\exposid{count_}@ = 0; // \expos + }; + + template + drop_view(R&&, range_difference_t) -> drop_view>; +} +\end{codeblock} + +\indexlibraryctor{drop_view}% +\begin{itemdecl} +constexpr drop_view(V base, range_difference_t count); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{count >= 0} is \tcode{true}. + +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{count_} with \tcode{count}. +\end{itemdescr} + +\indexlibrarymember{begin}{drop_view}% +\begin{itemdecl} +constexpr auto begin() + requires (!(@\exposconcept{simple-view}@ && + @\libconcept{random_access_range}@ && @\libconcept{sized_range}@)); +constexpr auto begin() const + requires @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{ranges::next(ranges::begin(\exposid{base_}), \exposid{count_}, ranges::end(\exposid{base_}))}. + +\pnum +\remarks +In order to provide the amortized constant-time complexity required +by the \libconcept{range} concept +when \tcode{drop_view} models \libconcept{forward_range}, +the first overload caches the result within the \tcode{drop_view} +for use on subsequent calls. +\begin{note} +Without this, +applying a \tcode{reverse_view} over a \tcode{drop_view} +would have quadratic iteration complexity. +\end{note} +\end{itemdescr} + +\rSec2[range.drop.while]{Drop while view} + +\rSec3[range.drop.while.overview]{Overview} + +\pnum +Given a unary predicate \tcode{pred} and a \libconcept{view} \tcode{r}, +\tcode{drop_while_view} produces a \libconcept{view} +of the range \range{ranges::find_if_not(r, pred)}{ranges::end(r)}. + +\pnum +\indexlibrarymember{drop_while}{views}% +The name \tcode{views::drop_while} +denotes a range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::drop_while(E, F)} +is expression-equivalent to \tcode{drop_while_view(E, F)}. + +\pnum +\begin{example} +\begin{codeblock} +constexpr auto source = " \t \t \t hello there"; +auto is_invisible = [](const auto x) { return x == ' ' || x == '\t'; }; +auto skip_ws = views::drop_while(source, is_invisible); +for (auto c : skip_ws) { + cout << c; // prints \tcode{hello there} with no leading space +} +\end{codeblock} +\end{example} + +\rSec3[range.drop.while.view]{Class template \tcode{drop_while_view}} + +\indexlibraryglobal{drop_while_view}% +\indexlibrarymember{base}{drop_while_view}% +\indexlibrarymember{end}{drop_while_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V, class Pred> + requires @\libconcept{input_range}@ && is_object_v && + @\libconcept{indirect_unary_predicate}@> + class drop_while_view : public view_interface> { + public: + drop_while_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr drop_while_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 auto begin(); + + constexpr auto end() { return ranges::end(@\exposid{base_}@); } + + private: + V @\exposid{base_}@ = V(); // \expos + @\placeholder{movable-box}@ @\exposid{pred_}@; @\itcorr[-1]@ // \expos + }; + + template + drop_while_view(R&&, Pred) -> drop_while_view, Pred>; +} +\end{codeblock} + +\indexlibraryctor{drop_while_view}% +\begin{itemdecl} +constexpr drop_while_view(V base, Pred pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{pred_} with \tcode{std::move(pred)}. +\end{itemdescr} + +\indexlibrarymember{pred}{drop_while_view}% +\begin{itemdecl} +constexpr const Pred& pred() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return *\exposid{pred_};} +\end{itemdescr} + +\indexlibrarymember{begin}{drop_while_view}% +\begin{itemdecl} +constexpr auto begin(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. + +\pnum +\returns +\tcode{ranges::find_if_not(\exposid{base_}, cref(*\exposid{pred_}))}. + +\pnum +\remarks +In order to provide the amortized constant-time complexity +required by the \libconcept{range} concept +when \tcode{drop_while_view} models \libconcept{forward_range}, +the first call caches the result within the \tcode{drop_while_view} +for use on subsequent calls. +\begin{note} +Without this, +applying a \tcode{reverse_view} over a \tcode{drop_while_view} +would have quadratic iteration complexity. +\end{note} +\end{itemdescr} + +\rSec2[range.join]{Join view} + +\rSec3[range.join.overview]{Overview} + +\pnum +\tcode{join_view} flattens a \libconcept{view} of ranges into a +\libconcept{view}. + +\pnum +\indexlibrarymember{join}{views}% +The name \tcode{views::join} denotes a +range adaptor object\iref{range.adaptor.object}. +Given a subexpression \tcode{E}, the expression +\tcode{views::join(E)} is expression-equivalent to +\tcode{join_view>\{E\}}. + +\pnum +\begin{example} +\begin{codeblock} +vector ss{"hello", " ", "world", "!"}; +for (char ch : ss | views::join) + cout << ch; // prints \tcode{hello world!} +\end{codeblock} +\end{example} + +\rSec3[range.join.view]{Class template \tcode{join_view}} + +\indexlibraryglobal{join_view}% +\indexlibrarymember{base}{join_view}% +\indexlibrarymember{begin}{join_view}% +\indexlibrarymember{end}{join_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ && @\libconcept{input_range}@> + class join_view : public view_interface> { + private: + using @\exposidnc{InnerRng}@ = range_reference_t; // \expos + + // \ref{range.join.iterator}, class template \tcode{join_view::\exposid{iterator}} + template + struct @\exposidnc{iterator}@; // \expos + + // \ref{range.join.sentinel}, class template \tcode{join_view::\exposid{sentinel}} + template + struct @\exposidnc{sentinel}@; // \expos + + V @\exposid{base_}@ = V(); // \expos + + @\exposidnc{non-propagating-cache}@> @\exposid{inner_}@; // \expos, present only + // when \tcode{!is_reference_v<\exposid{InnerRng}>} + + public: + join_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit join_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() { + constexpr bool use_const = @\exposconcept{simple-view}@ && + is_reference_v<@\exposid{InnerRng}@>; + return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + } + + constexpr auto begin() const + requires @\libconcept{input_range}@ && + is_reference_v> + { return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; } + + constexpr auto end() { + if constexpr (@\libconcept{forward_range}@ && + is_reference_v<@\exposid{InnerRng}@> && @\libconcept{forward_range}@<@\exposid{InnerRng}@> && + @\libconcept{common_range}@ && @\libconcept{common_range}@<@\exposid{InnerRng}@>) + return @\exposid{iterator}@<@\exposconcept{simple-view}@>{*this, ranges::end(@\exposid{base_}@)}; + else + return @\exposid{sentinel}@<@\exposconcept{simple-view}@>{*this}; + } + + constexpr auto end() const + requires @\libconcept{input_range}@ && + is_reference_v> { + if constexpr (@\libconcept{forward_range}@ && + @\libconcept{forward_range}@> && + @\libconcept{common_range}@ && + @\libconcept{common_range}@>) + return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; + else + return @\exposid{sentinel}@{*this}; + } + }; + + template + explicit join_view(R&&) -> join_view>; +} +\end{codeblock} + +\indexlibraryctor{join_view}% +\begin{itemdecl} +constexpr explicit join_view(V base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\rSec3[range.join.iterator]{Class template \tcode{join_view::\exposid{iterator}}} + +\indexlibraryglobal{join_view::iterator}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ && @\libconcept{input_range}@> + template + struct join_view::@\exposid{iterator}@ { + private: + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{OuterIter}@ = iterator_t<@\exposidnc{Base}@>; // \expos + using @\exposidnc{InnerIter}@ = iterator_t>; // \expos + + static constexpr bool @\exposidnc{ref-is-glvalue}@ = // \expos + is_reference_v>; + + @\exposidnc{OuterIter}@ @\exposid{outer_}@ = @\exposidnc{OuterIter}@(); // \expos + @\exposidnc{InnerIter}@ @\exposid{inner_}@ = @\exposidnc{InnerIter}@(); // \expos + @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + + constexpr void @\exposidnc{satisfy}@(); // \expos + + public: + using iterator_concept = @\seebelow@; + using iterator_category = @\seebelow@; // not always present + using value_type = range_value_t>; + using difference_type = @\seebelow@; + + @\exposid{iterator}@() requires @\libconcept{default_initializable}@<@\exposid{OuterIter}@> && + @\itcorr[-2]\libconcept{default_initializable}@<@\exposid{InnerIter}@> = default; + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer); + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && + @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && + @\libconcept{convertible_to}@, @\exposid{InnerIter}@>; + + constexpr decltype(auto) operator*() const { return *@\exposid{inner_}@; } + + constexpr @\exposid{InnerIter}@ operator->() const + requires @\exposconcept{has-arrow}@<@\exposid{InnerIter}@> && @\libconcept{copyable}@<@\exposid{InnerIter}@>; + + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && + @\libconcept{forward_range}@>; + + constexpr @\exposid{iterator}@& operator--() + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\libconcept{bidirectional_range}@> && + @\libconcept{common_range}@>; + + constexpr @\exposid{iterator}@ operator--(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\libconcept{bidirectional_range}@> && + @\libconcept{common_range}@>; + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@> && + @\libconcept{equality_comparable}@>>; + + friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{inner_}@))) { + return ranges::iter_move(i.@\exposid{inner_}@); + } + + friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{inner_}@, y.@\exposid{inner_}@))) + requires @\libconcept{indirectly_swappable}@<@\exposid{InnerIter}@>; + }; +} +\end{codeblock} + +\pnum +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +\begin{itemize} +\item If \exposid{ref-is-glvalue} is \tcode{true}, + \exposid{Base} models \libconcept{bidirectional_range}, and + \tcode{range_reference_t<\exposid{Base}>} models + both \libconcept{bidirectional_range} and \libconcept{common_range}, + then \tcode{iterator_concept} denotes \tcode{bidirectio\-nal_iterator_tag}. +\item Otherwise, if \exposid{ref-is-glvalue} is \tcode{true} and + \exposid{Base} and \tcode{range_reference_t<\exposid{Base}>} + each model \libconceptx{for\-ward_range}{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{ref-is-glvalue} is \tcode{true}, +\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: +\begin{itemize} +\item Let \placeholder{OUTERC} denote + \tcode{iterator_traits>::iterator_category}, and + let \placeholder{INNERC} denote + \tcode{iterator_traits>>::iterator_category}. +\item If + \placeholder{OUTERC} and \placeholder{INNERC} each model + \tcode{\libconcept{derived_from}} and + \tcode{range_reference_t<\exposid{Base}>} models \libconcept{common_range}, + \tcode{iterator_category} denotes \tcode{bidirectional_iterator_tag}. +\item Otherwise, if + \placeholder{OUTERC} and \placeholder{INNERC} each model + \tcode{\libconcept{derived_from}}, \tcode{iter\-ator_category} + denotes \tcode{forward_iterator_tag}. +\item Otherwise, + \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\pnum +\tcode{iterator::difference_type} denotes the type: +\begin{codeblock} +common_type_t< + range_difference_t<@\exposid{Base}@>, + range_difference_t>> +\end{codeblock} + +\pnum +\tcode{join_view} iterators use the \exposid{satisfy} function to skip over +empty inner ranges. + +\begin{itemdecl} +constexpr void @\exposid{satisfy}@(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto update_inner = [this](const iterator_t<@\exposid{Base}@>& x) -> auto&& { + if constexpr (@\exposid{ref-is-glvalue}@) // \tcode{*x} is a reference + return *x; + else + return @\exposid{parent_}@->@\exposid{inner_}@.@\exposid{emplace-deref}@(x); +}; + +for (; @\exposid{outer_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@); ++@\exposid{outer_}@) { + auto&& inner = update_inner(@\exposid{outer_}@); + @\exposid{inner_}@ = ranges::begin(inner); + if (@\exposid{inner_}@ != ranges::end(inner)) + return; +} +if constexpr (@\exposid{ref-is-glvalue}@) + @\exposid{inner_}@ = @\exposid{InnerIter}@(); +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{join_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{outer_} with \tcode{std::move(outer)} and +\exposid{parent_} with \tcode{addressof(parent)}; then calls \tcode{\exposid{satisfy}()}. +\end{itemdescr} + +\indexlibraryctor{join_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && + @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && + @\libconcept{convertible_to}@, @\exposid{InnerIter}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{outer_} with \tcode{std::move(i.\exposid{outer_})}, +\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}, and +\exposid{parent_} with \tcode{i.\exposid{parent_}}. +\end{itemdescr} + +\indexlibrarymember{operator->}{join_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{InnerIter}@ operator->() const + requires @\exposconcept{has-arrow}@<@\exposid{InnerIter}@> && @\libconcept{copyable}@<@\exposid{InnerIter}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{return \exposid{inner_};} +\end{itemdescr} + +\indexlibrarymember{operator++}{join_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{inner-range}} be: +\begin{itemize} +\item If \exposid{ref-is-glvalue} is \tcode{true}, \tcode{*\exposid{outer_}}. +\item Otherwise, \tcode{*\exposid{parent_}->\exposid{inner_}}. +\end{itemize} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto&& inner_rng = @\placeholder{inner-range}@; +if (++@\exposid{inner_}@ == ranges::end(inner_rng)) { + ++@\exposid{outer_}@; + @\exposid{satisfy}@(); +} +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator++}{join_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{++*this}. +\end{itemdescr} + +\indexlibrarymember{operator++}{join_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && + @\libconcept{forward_range}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{join_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\libconcept{bidirectional_range}@> && + @\libconcept{common_range}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (@\exposid{outer_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) + @\exposid{inner_}@ = ranges::end(*--@\exposid{outer_}@); +while (@\exposid{inner_}@ == ranges::begin(*@\exposid{outer_}@)) + @\exposid{inner_}@ = ranges::end(*--@\exposid{outer_}@); +--@\exposid{inner_}@; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator--}{join_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator--(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\libconcept{bidirectional_range}@> && + @\libconcept{common_range}@>; \end{itemdecl} \begin{itemdescr} @@ -4133,209 +6769,387 @@ \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator==}{filter_view::iterator}% +\indexlibrarymember{operator==}{join_view::iterator}% \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; + requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@> && + @\libconcept{equality_comparable}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} +Equivalent to: +\tcode{return x.\exposid{outer_} == y.\exposid{outer_} \&\& x.\exposid{inner_} == y.\exposid{inner_};} \end{itemdescr} -\indexlibrarymember{iter_move}{filter_view::iterator}% +\indexlibrarymember{iter_swap}{join_view::iterator}% \begin{itemdecl} -friend constexpr range_rvalue_reference_t 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{inner_}@, y.@\exposid{inner_}@))) + requires @\libconcept{indirectly_swappable}@<@\exposid{InnerIter}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} +Equivalent to: \tcode{return ranges::iter_swap(x.\exposid{inner_}, y.\exposid{inner_});} \end{itemdescr} -\indexlibrarymember{iter_swap}{filter_view::iterator}% +\rSec3[range.join.sentinel]{Class template \tcode{join_view::\exposid{sentinel}}} + +\indexlibraryglobal{join_view::sentinel}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V> + requires @\libconcept{view}@ && @\libconcept{input_range}@> + template + struct join_view::@\exposid{sentinel}@ { + private: + using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos + 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}@(@\exposid{Parent}@& parent); + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + + template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + }; +} +\end{codeblock} + +\indexlibraryctor{join_view::sentinel}% \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}@>; +constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. +\end{itemdescr} + +\indexlibraryctor{join_view::sentinel}% +\begin{itemdecl} +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(s.\exposid{end_})}. +\end{itemdescr} + +\indexlibrarymember{operator==}{join_view::sentinel}%3431 + +\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} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.\exposid{outer_} == y.\exposid{end_};} +\end{itemdescr} + +\rSec2[range.join.with]{Join with view} + +\rSec3[range.join.with.overview]{Overview} + +\pnum +\tcode{join_with_view} takes a \libconcept{view} and a delimiter, and +flattens the \libconcept{view}, +inserting every element of the delimiter +in between elements of the \libconcept{view}. +The delimiter can be a single element or a \libconcept{view} of elements. + \pnum -\effects -Equivalent to \tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_})}. -\end{itemdescr} +\indexlibrarymember{join_with}{views}% +The name \tcode{views::join_with} denotes +a range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::join_with(E, F)} is expression-equivalent to +\tcode{join_with_view(E, F)}. -\rSec3[range.filter.sentinel]{Class \tcode{filter_view::\exposid{sentinel}}} +\pnum +\begin{example} +\begin{codeblock} +vector vs = {"the", "quick", "brown", "fox"}; +for (char c : vs | views::join_with('-')) { + cout << c; +} +// The above prints \tcode{the-quick-brown-fox} +\end{codeblock} +\end{example} + +\rSec3[range.join.with.view]{Class template \tcode{join_with_view}} -\indexlibrarymember{sentinel}{filter_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> - requires @\libconcept{view}@ && is_object_v - class filter_view::@\exposid{sentinel}@ { - private: - sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos + 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> + class join_with_view : public view_interface> { + using @\exposid{InnerRng}@ = range_reference_t; // \expos + + V @\exposid{base_}@ = V(); // \expos + @\exposid{non-propagating-cache}@> @\exposid{inner_}@; // \expos, present only + // when \tcode{!is_reference_v<\exposid{InnerRng}>} + Pattern @\exposid{pattern_}@ = Pattern(); // \expos + + // \ref{range.join.with.iterator}, class template \tcode{join_with_view::\exposid{iterator}} + template struct @\exposid{iterator}@; // \expos + + // \ref{range.join.with.sentinel}, class template \tcode{join_with_view::\exposid{sentinel}} + template struct @\exposid{sentinel}@; // \expos public: - @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(filter_view& parent); + join_with_view() + requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr sentinel_t base() const; + constexpr join_with_view(V base, Pattern pattern); - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + template<@\libconcept{input_range}@ R> + requires @\libconcept{constructible_from}@> && + @\libconcept{constructible_from}@>> + constexpr join_with_view(R&& r, range_value_t<@\exposid{InnerRng}@> e); + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + + constexpr auto begin() { + constexpr bool use_const = + @\exposconcept{simple-view}@ && is_reference_v<@\exposid{InnerRng}@> && @\exposconcept{simple-view}@; + return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + } + constexpr auto begin() const + requires @\libconcept{input_range}@ && + @\libconcept{forward_range}@ && + is_reference_v> { + return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + } + + constexpr auto end() { + if constexpr (@\libconcept{forward_range}@ && + is_reference_v<@\exposid{InnerRng}@> && @\libconcept{forward_range}@<@\exposid{InnerRng}@> && + @\libconcept{common_range}@ && @\libconcept{common_range}@<@\exposid{InnerRng}@>) + return @\exposid{iterator}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@>{*this, ranges::end(@\exposid{base_}@)}; + else + return @\exposid{sentinel}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@>{*this}; + } + constexpr auto end() const + requires @\libconcept{input_range}@ && @\libconcept{forward_range}@ && + is_reference_v> { + using InnerConstRng = range_reference_t; + if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && + @\libconcept{common_range}@ && @\libconcept{common_range}@) + return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; + else + return @\exposid{sentinel}@{*this}; + } }; + + template + join_with_view(R&&, P&&) -> join_with_view, views::all_t

>; + + template<@\libconcept{input_range}@ R> + join_with_view(R&&, range_value_t>) + -> join_with_view, single_view>>>; } \end{codeblock} -\indexlibraryctor{filter_view::sentinel}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(filter_view& parent); +constexpr join_with_view(V base, Pattern pattern); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{pattern_} with \tcode{std::move(pattern)}. \end{itemdescr} -\indexlibrarymember{base}{filter_view::sentinel}% \begin{itemdecl} -constexpr sentinel_t base() const; +template<@\libconcept{input_range}@ R> + requires @\libconcept{constructible_from}@> && + @\libconcept{constructible_from}@>> +constexpr join_with_view(R&& r, range_value_t<@\exposid{InnerRng}@> e); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{end_};} +Initializes \exposid{base_} with \tcode{views::all(std::forward(r))} and +\exposid{pattern_} with \tcode{views::sin\-gle(std::move(e))}. \end{itemdescr} -\indexlibrarymember{operator==}{filter_view::sentinel}% -\begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); -\end{itemdecl} +\rSec3[range.join.with.iterator]{Class template \tcode{join_with_view::\exposid{iterator}}} -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} -\end{itemdescr} +\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> + template + class join_with_view::@\exposid{iterator}@ { + using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + using @\exposid{InnerBase}@ = range_reference_t<@\exposid{Base}@>; // \expos + using @\exposid{PatternBase}@ = @\exposid{maybe-const}@; // \expos -\rSec2[range.transform]{Transform view} + using @\exposid{OuterIter}@ = iterator_t<@\exposid{Base}@>; // \expos + using @\exposid{InnerIter}@ = iterator_t<@\exposid{InnerBase}@>; // \expos + using @\exposid{PatternIter}@ = iterator_t<@\exposid{PatternBase}@>; // \expos -\rSec3[range.transform.overview]{Overview} + static constexpr bool @\exposid{ref-is-glvalue}@ = is_reference_v<@\exposid{InnerBase}@>; // \expos -\pnum -\tcode{transform_view} presents -a \libconcept{view} of an underlying sequence after -applying a transformation function to each element. + @\exposid{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + @\exposid{OuterIter}@ @\exposid{outer_it_}@ = @\exposid{OuterIter}@(); // \expos + variant<@\exposid{PatternIter}@, @\exposid{InnerIter}@> @\exposid{inner_it_}@; // \expos -\pnum -\indexlibrarymember{transform}{views}% -The name \tcode{views::transform} denotes a -range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{F}, the expression -\tcode{views::transform(E, F)} is expression-equivalent to -\tcode{transform_view(E, F)}. + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> outer); // \expos + constexpr auto&& @\exposid{update-inner}@(const @\exposid{OuterIter}@&); // \expos + constexpr auto&& @\exposid{get-inner}@(const @\exposid{OuterIter}@&); // \expos + constexpr void @\exposid{satisfy}@(); // \expos -\pnum -\begin{example} -\begin{codeblock} -vector is{ 0, 1, 2, 3, 4 }; -auto squares = views::transform(is, [](int i) { return i * i; }); -for (int i : squares) - cout << i << ' '; // prints: 0 1 4 9 16 -\end{codeblock} -\end{example} + public: + using iterator_concept = @\seebelow@; + using iterator_category = @\seebelow@; // not always present + using value_type = @\seebelow@; + using difference_type = @\seebelow@; -\rSec3[range.transform.view]{Class template \tcode{transform_view}} + @\exposid{iterator}@() requires @\libconcept{default_initializable}@<@\exposid{OuterIter}@> = default; + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && + @\libconcept{convertible_to}@, @\exposid{InnerIter}@> && + @\libconcept{convertible_to}@, @\exposid{PatternIter}@>; -\indexlibraryglobal{transform_view}% -\indexlibrarymember{base}{transform_view}% -\indexlibrarymember{size}{transform_view}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{copy_constructible}@ F> - requires @\libconcept{view}@ && is_object_v && - @\libconcept{regular_invocable}@> && - @\exposconcept{can-reference}@>> - class transform_view : public view_interface> { - private: - // \ref{range.transform.iterator}, class template \tcode{transform_view::\exposid{iterator}} - template struct @\exposid{iterator}@; // \expos + constexpr decltype(auto) operator*() const; - // \ref{range.transform.sentinel}, class template \tcode{transform_view::\exposid{sentinel}} - template struct @\exposid{sentinel}@; // \expos + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_iterator}@<@\exposid{OuterIter}@> && + @\libconcept{forward_iterator}@<@\exposid{InnerIter}@>; - V @\exposid{base_}@ = V(); // \expos - @\placeholdernc{copyable-box}@ @\exposid{fun_}@; // \expos + constexpr @\exposid{iterator}@& operator--() + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; + constexpr @\exposid{iterator}@ operator--(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; - public: - transform_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr transform_view(V base, F fun); + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@<@\exposid{OuterIter}@> && + @\libconcept{equality_comparable}@<@\exposid{InnerIter}@>; - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& x) { + using rvalue_reference = common_reference_t< + iter_rvalue_reference_t<@\exposid{InnerIter}@>, + iter_rvalue_reference_t<@\exposid{PatternIter}@>>; + return visit(ranges::iter_move, x.@\exposid{inner_it_}@); + } - constexpr @\exposid{iterator}@ begin(); - constexpr @\exposid{iterator}@ begin() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@>; + friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{indirectly_swappable}@<@\exposid{InnerIter}@, @\exposid{PatternIter}@> { + visit(ranges::iter_swap, x.@\exposid{inner_it_}@, y.@\exposid{inner_it_}@); + } + }; +} +\end{codeblock} - constexpr @\exposid{sentinel}@ end(); - constexpr @\exposid{iterator}@ end() requires @\libconcept{common_range}@; - constexpr @\exposid{sentinel}@ end() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@>; - constexpr @\exposid{iterator}@ end() const - requires @\libconcept{common_range}@ && - @\libconcept{regular_invocable}@>; +\pnum +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: +\begin{itemize} +\item +If \exposid{ref-is-glvalue} is \tcode{true}, +\exposid{Base} models \libconcept{bidirectional_range}, and +\exposid{InnerBase} and \exposid{PatternBase} +each model \exposconcept{bidirectional-common}, +then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +\item +Otherwise, if \exposid{ref-is-glvalue} is \tcode{true} and +\exposid{Base} and \exposid{InnerBase} each model \libconcept{forward_range}, +then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} - 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_}@); } - }; +\pnum +The member \grammarterm{typedef-name} \tcode{iterator_category} is defined +if and only if \exposid{ref-is-glvalue} is \tcode{true}, and +\exposid{Base} and \exposid{InnerBase} each model \libconcept{forward_range}. +In that case, +\tcode{\exposid{iterator}::iterator_category} is defined as follows: - template - transform_view(R&&, F) -> transform_view, F>; -} +\begin{itemize} +\item +Let \placeholder{OUTERC} denote +\tcode{iterator_traits<\exposid{OuterIter}>::iterator_category}, +let \placeholder{INNERC} denote +\tcode{iterator_traits<\exposid{InnerIter}>::iterator_category}, and +let \placeholder{PATTERNC} denote +\tcode{iterator_-\linebreak traits<\exposid{PatternIter}>::iterator_category}. +\item +If +\begin{codeblock} +is_lvalue_reference_v, + iter_reference_t<@\exposid{PatternIter}@>>> \end{codeblock} +is \tcode{false}, +\tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\item +Otherwise, +if \placeholder{OUTERC}, \placeholder{INNERC}, and \placeholder{PATTERNC} +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}. +\item +Otherwise, +if \placeholder{OUTERC}, \placeholder{INNERC}, and \placeholder{PATTERNC} +each model \tcode{\libconcept{derived_from}}, +\tcode{iterator_category} denotes \tcode{forward_iterator_tag}. +\item +Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\end{itemize} -\indexlibraryctor{transform_view}% -\begin{itemdecl} -constexpr transform_view(V base, F fun); -\end{itemdecl} - -\begin{itemdescr} \pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{fun_} with \tcode{std::move(fun)}. -\end{itemdescr} - -\indexlibrarymember{begin}{transform_view}% -\begin{itemdecl} -constexpr @\exposid{iterator}@ begin(); -\end{itemdecl} +\tcode{\exposid{iterator}::value_type} denotes the type: +\begin{codeblock} +common_type_t, iter_value_t<@\exposid{PatternIter}@>> +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Equivalent to: +\tcode{\exposid{iterator}::difference_type} denotes the type: \begin{codeblock} -return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; +common_type_t< + iter_difference_t<@\exposid{OuterIter}@>, + iter_difference_t<@\exposid{InnerIter}@>, + iter_difference_t<@\exposid{PatternIter}@>> \end{codeblock} -\end{itemdescr} -\indexlibrarymember{begin}{transform_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@ begin() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@>; +constexpr auto&& @\exposid{update-inner}@(const @\exposid{OuterIter}@& x); \end{itemdecl} \begin{itemdescr} @@ -4343,13 +7157,15 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; +if constexpr (@\exposid{ref-is-glvalue}@) + return *x; +else + return @\exposid{parent_}@->@\exposid{inner_}@.@\exposid{emplace-deref}@(x); \end{codeblock} \end{itemdescr} -\indexlibrarymember{end}{transform_view}% \begin{itemdecl} -constexpr @\exposid{sentinel}@ end(); +constexpr auto&& @\exposid{get-inner}@(const @\exposid{OuterIter}@& x); \end{itemdecl} \begin{itemdescr} @@ -4357,13 +7173,15 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; +if constexpr (@\exposid{ref-is-glvalue}@) + return *x; +else + return *@\exposid{parent_}@->@\exposid{inner_}@; \end{codeblock} \end{itemdescr} -\indexlibrarymember{end}{transform_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@ end() requires @\libconcept{common_range}@; +constexpr void @\exposid{satisfy}@(); \end{itemdecl} \begin{itemdescr} @@ -4371,213 +7189,190 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; +while (true) { + if (@\exposid{inner_it_}@.index() == 0) { + if (std::get<0>(@\exposid{inner_it_}@) != ranges::end(@\exposid{parent_}@->@\exposid{pattern_}@)) + break; + auto&& inner = @\exposid{update-inner}@(@\exposid{outer_it_}@); + @\exposid{inner_it_}@.emplace<1>(ranges::begin(inner)); + } else { + auto&& inner = @\exposid{get-inner}@(@\exposid{outer_it_}@); + if (std::get<1>(@\exposid{inner_it_}@) != ranges::end(inner)) + break; + if (++@\exposid{outer_it_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { + if constexpr (@\exposid{ref-is-glvalue}@) + @\exposid{inner_it_}@.emplace<0>(); + break; + } + @\exposid{inner_it_}@.emplace<0>(ranges::begin(@\exposid{parent_}@->@\exposid{pattern_}@)); + } +} \end{codeblock} + +\begin{note} +\tcode{join_with_view} iterators use the \exposid{satisfy} function +to skip over empty inner ranges. +\end{note} \end{itemdescr} -\indexlibrarymember{end}{transform_view}% \begin{itemdecl} -constexpr @\exposid{sentinel}@ end() const - requires @\libconcept{range}@ && - @\libconcept{regular_invocable}@>; +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> outer); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: +Initializes \exposid{parent_} with \tcode{addressof(parent)} and +\exposid{outer_it_} with \tcode{std::move(outer)}. +Then, equivalent to: \begin{codeblock} -return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; +if (@\exposid{outer_it_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { + auto&& inner = @\exposid{update-inner}@(@\exposid{outer_it_}@); + @\exposid{inner_it_}@.emplace<1>(ranges::begin(inner)); + @\exposidnc{satisfy}@(); +} \end{codeblock} \end{itemdescr} -\indexlibrarymember{end}{transform_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@ end() const - requires @\libconcept{common_range}@ && - @\libconcept{regular_invocable}@>; +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && + @\libconcept{convertible_to}@, @\exposid{InnerIter}@> && + @\libconcept{convertible_to}@, @\exposid{PatternIter}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: +Initializes \exposid{outer_it_} with +\tcode{std::move(i.\exposid{outer_it_})} and +\exposid{parent_} with \tcode{i.\exposid{parent_}}. +Then, equivalent to: \begin{codeblock} -return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; +if (i.@\exposid{inner_it_}@.index() == 0) + @\exposid{inner_it_}@.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_}@))); \end{codeblock} \end{itemdescr} -\rSec3[range.transform.iterator]{Class template \tcode{transform_view::\exposid{iterator}}} - -\indexlibraryglobal{transform_view::iterator}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{copy_constructible}@ F> - requires @\libconcept{view}@ && is_object_v && - @\libconcept{regular_invocable}@> && - @\exposconcept{can-reference}@>> - template - class transform_view::@\exposid{iterator}@ { - private: - using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - iterator_t<@\exposidnc{Base}@> @\exposid{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos - @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos - - public: - using iterator_concept = @\seebelownc@; - using iterator_category = @\seebelownc@; // 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 @\exposid{iterator}@(@\exposid{Parent}@& parent, 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 - noexcept(noexcept(invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *@\exposid{current_}@))) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *@\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 invoke(*@\exposid{parent_}@->@\exposid{fun_}@, @\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+(@\exposid{iterator}@ i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr @\exposid{iterator}@ operator+(difference_type n, @\exposid{iterator}@ i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - - friend constexpr @\exposid{iterator}@ operator-(@\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}@>>; - }; -} -\end{codeblock} - -\pnum -\tcode{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} +\begin{itemdecl} +constexpr decltype(auto) operator*() const; +\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{iterator::iterator_category} is defined as follows: -Let \tcode{C} denote the type -\tcode{iterator_traits>::iterator_category}. -\begin{itemize} -\item -If \tcode{is_lvalue_reference_v>>} -is \tcode{true}, then -\begin{itemize} -\item -if \tcode{C} models \tcode{\libconcept{derived_from}}, -\tcode{iterator_category} denotes \tcode{random_access_iterator_tag}; +\effects +Equivalent to: +\begin{codeblock} +using reference = + common_reference_t, iter_reference_t<@\exposid{PatternIter}@>>; +return visit([](auto& it) -> reference { return *it; }, @\exposid{inner_it_}@); +\end{codeblock} +\end{itemdescr} -\item -otherwise, -\tcode{iterator_category} denotes \tcode{C}. -\end{itemize} +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} -\item -Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\end{itemize} +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +visit([](auto& it){ ++it; }, @\exposid{inner_it_}@); +@\exposidnc{satisfy}@(); +return *this; +\end{codeblock} +\end{itemdescr} -\indexlibrarymember{iterator}{transform_view::iterator} \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current); +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(current)} and -\exposid{parent_} with \tcode{addressof(parent)}. +Equivalent to \tcode{++*this}. \end{itemdescr} -\indexlibraryctor{transform_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@ operator++(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_iterator}@<@\exposid{OuterIter}@> && @\libconcept{forward_iterator}@<@\exposid{InnerIter}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})} and -\exposid{parent_} with \tcode{i.\exposid{parent_}}. +Equivalent to: +\begin{codeblock} +@\exposid{iterator}@ tmp = *this; +++*this; +return tmp; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{transform_view::iterator}% \begin{itemdecl} -constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +constexpr @\exposid{iterator}@& operator--() + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{current_};} +Equivalent to: +\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)); +} + +while (true) { + if (@\exposid{inner_it_}@.index() == 0) { + 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)); + } else { + break; + } + } else { + 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_}@)); + } else { + break; + } + } +} +visit([](auto& it){ --it; }, @\exposid{inner_it_}@); +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{transform_view::iterator}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() &&; +constexpr @\exposid{iterator}@ operator--(int) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && + @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return std::move(current_);} +Equivalent to: +\begin{codeblock} +@\exposid{iterator}@ tmp = *this; +--*this; +return tmp; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{transform_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@<@\exposid{OuterIter}@> && + @\libconcept{equality_comparable}@<@\exposid{InnerIter}@>; \end{itemdecl} \begin{itemdescr} @@ -4585,1142 +7380,1185 @@ \effects Equivalent to: \begin{codeblock} -++@\exposid{current_}@; -return *this; +return x.@\exposid{outer_it_}@ == y.@\exposid{outer_it_}@ && x.@\exposid{inner_it_}@ == y.@\exposid{inner_it_}@; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{transform_view::iterator}% +\rSec3[range.join.with.sentinel]{Class template \tcode{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> + template + class join_with_view::@\exposid{sentinel}@ { + using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos + using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + + constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); // \expos + + public: + @\exposid{sentinel}@() = default; + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + + template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + }; +} +\end{codeblock} + \begin{itemdecl} -constexpr void operator++(int); +constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(s.\exposid{end_})}. +\end{itemdescr} + +\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{++current_}. +Equivalent to: \tcode{return x.\exposid{outer_it_} == y.\exposid{end_};} \end{itemdescr} -\indexlibrarymember{operator++}{transform_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; -\end{itemdecl} +\rSec2[range.lazy.split]{Lazy split view} + +\rSec3[range.lazy.split.overview]{Overview} + +\pnum +\tcode{lazy_split_view} takes a \libconcept{view} and a delimiter, and splits +the \libconcept{view} into subranges on the delimiter. The delimiter can be +a single element or a \libconcept{view} of elements. + +\pnum +\indexlibrarymember{lazy_split}{views}% +The name \tcode{views::lazy_split} denotes a +range adaptor object\iref{range.adaptor.object}. +Given subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::lazy_split(E, F)} is expression-equivalent to +\tcode{lazy_split_view(E, F)}. + +\pnum +\begin{example} +\begin{codeblock} +string str{"the quick brown fox"}; +for (auto word : str | views::lazy_split(' ')) { + for (char ch : word) + cout << ch; + cout << '*'; +} +// The above prints \tcode{the*quick*brown*fox*} +\end{codeblock} +\end{example} + +\rSec3[range.lazy.split.view]{Class template \tcode{lazy_split_view}} + +\indexlibraryglobal{lazy_split_view}% +\indexlibrarymember{base}{lazy_split_view}% +\indexlibrarymember{begin}{lazy_split_view}% +\indexlibrarymember{end}{lazy_split_view}% +\begin{codeblock} +namespace std::ranges { + template struct @\exposidnc{require-constant}@; // \expos + + template + concept @\defexposconceptnc{tiny-range}@ = // \expos + @\libconcept{sized_range}@ && + requires { typename @\exposid{require-constant}@::size()>; } && + (remove_reference_t::size() <= 1); + + template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> + requires @\libconcept{view}@ && @\libconcept{view}@ && + @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && + (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) + class lazy_split_view : public view_interface> { + private: + V @\exposid{base_}@ = V(); // \expos + Pattern @\exposid{pattern_}@ = Pattern(); // \expos + + @\exposidnc{non-propagating-cache}@> @\exposid{current_}@; // \expos, present only + // if \tcode{!\libconcept{forward_range}} + + // \ref{range.lazy.split.outer}, class template \tcode{lazy_split_view::\exposid{outer-iterator}} + template struct @\exposidnc{outer-iterator}@; // \expos + + // \ref{range.lazy.split.inner}, class template \tcode{lazy_split_view::\exposid{inner-iterator}} + template struct @\exposidnc{inner-iterator}@; // \expos + + public: + lazy_split_view() + requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr lazy_split_view(V base, Pattern pattern); + + template<@\libconcept{input_range}@ R> + requires @\libconcept{constructible_from}@> && + @\libconcept{constructible_from}@>> + constexpr lazy_split_view(R&& r, range_value_t e); + + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\exposid{base_}@); } + + constexpr auto begin() { + if constexpr (@\libconcept{forward_range}@) { + return @\exposid{outer-iterator}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@> + {*this, ranges::begin(@\exposid{base_}@)}; + } else { + @\exposid{current_}@ = ranges::begin(@\exposid{base_}@); + return @\exposid{outer-iterator}@{*this}; + } + } + + constexpr auto begin() const requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ { + return @\exposid{outer-iterator}@{*this, ranges::begin(@\exposid{base_}@)}; + } + + constexpr auto end() requires @\libconcept{forward_range}@ && @\libconcept{common_range}@ { + return @\exposid{outer-iterator}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@> + {*this, ranges::end(@\exposid{base_}@)}; + } + + constexpr auto end() const { + if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && @\libconcept{common_range}@) + return @\exposid{outer-iterator}@{*this, ranges::end(@\exposid{base_}@)}; + else + return default_sentinel; + } + }; + + template + lazy_split_view(R&&, P&&) -> lazy_split_view, views::all_t

>; -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; -++*this; -return tmp; + template<@\libconcept{input_range}@ R> + lazy_split_view(R&&, range_value_t) + -> lazy_split_view, single_view>>; +} \end{codeblock} -\end{itemdescr} -\indexlibrarymember{operator--}{transform_view::iterator}% +\indexlibraryctor{lazy_split_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr lazy_split_view(V base, Pattern pattern); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} ---@\exposid{current_}@; -return *this; -\end{codeblock} +Initializes \exposid{base_} with \tcode{std::move(base)}, and +\exposid{pattern_} with \tcode{std::move(pattern)}. \end{itemdescr} -\indexlibrarymember{operator--}{transform_view::iterator}% +\indexlibraryctor{lazy_split_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +template<@\libconcept{input_range}@ R> + requires @\libconcept{constructible_from}@> && + @\libconcept{constructible_from}@>> +constexpr lazy_split_view(R&& r, range_value_t e); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; ---*this; -return tmp; -\end{codeblock} +Initializes \exposid{base_} with \tcode{views::all(std::forward(r))}, and +\exposid{pattern_} with \tcode{views::\linebreak single(std::move(e))}. \end{itemdescr} -\indexlibrarymember{operator+=}{transform_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} +\rSec3[range.lazy.split.outer]{Class template \tcode{lazy_split_view::\exposid{outer-iterator}}} -\begin{itemdescr} -\pnum -\effects -Equivalent to: +\indexlibraryglobal{lazy_split_view::\exposid{outer-iterator}}% \begin{codeblock} -@\exposid{current_}@ += n; -return *this; -\end{codeblock} -\end{itemdescr} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> + requires @\libconcept{view}@ && @\libconcept{view}@ && + @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && + (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) + template + struct lazy_split_view::@\exposid{outer-iterator}@ { + private: + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos -\indexlibrarymember{operator-=}{transform_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} + iterator_t<@\exposidnc{Base}@> @\exposid{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos, present only + // if \tcode{V} models \libconcept{forward_range} -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{current_}@ -= n; -return *this; -\end{codeblock} -\end{itemdescr} + bool @\exposid{trailing_empty_}@ = false; // \expos -\indexlibrarymember{operator==}{transform_view::iterator}% -\begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; -\end{itemdecl} + public: + using iterator_concept = + conditional_t<@\libconcept{forward_range}@<@\exposid{Base}@>, forward_iterator_tag, input_iterator_tag>; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} -\end{itemdescr} + using iterator_category = input_iterator_tag; // present only if \exposid{Base} + // models \libconcept{forward_range} -\indexlibrarymember{operator<}{transform_view::iterator}% -\begin{itemdecl} -friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} + // \ref{range.lazy.split.outer.value}, class \tcode{lazy_split_view::\exposid{outer-iterator}::value_type} + struct value_type; + using difference_type = range_difference_t<@\exposid{Base}@>; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} < y.\exposid{current_};} -\end{itemdescr} + @\exposid{outer-iterator}@() = default; + constexpr explicit @\exposid{outer-iterator}@(@\exposid{Parent}@& parent) + requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); + constexpr @\exposid{outer-iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; + constexpr @\exposid{outer-iterator}@(@\exposid{outer-iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; -\indexlibrarymember{operator>}{transform_view::iterator}% -\begin{itemdecl} -friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} + constexpr value_type operator*() const; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return y < x;} -\end{itemdescr} + constexpr @\exposid{outer-iterator}@& operator++(); + constexpr decltype(auto) operator++(int) { + if constexpr (@\libconcept{forward_range}@<@\exposid{Base}@>) { + auto tmp = *this; + ++*this; + return tmp; + } else + ++*this; + } -\indexlibrarymember{operator<=}{transform_view::iterator}% -\begin{itemdecl} -friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} + friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, const @\exposid{outer-iterator}@& y) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; + + friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); + }; +} +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return !(y < x);} -\end{itemdescr} +Many of the specifications in \ref{range.lazy.split} refer to the notional member +\placeholder{current} of \exposid{outer-iterator}. +\placeholder{current} is equivalent to \exposid{current_} if \tcode{V} +models \libconcept{forward_range}, and \tcode{*\exposid{parent_}->\exposid{current_}} otherwise. -\indexlibrarymember{operator>=}{transform_view::iterator}% +\indexlibraryctor{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr explicit @\exposid{outer-iterator}@(@\exposid{Parent}@& parent) + requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(x < y);} +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} -\indexlibrarymember{operator<=>}{transform_view::iterator}% +\indexlibraryctor{lazy_split_view::\exposid{outer-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{outer-iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};} +Initializes \exposid{parent_} with \tcode{addressof(parent)} +and \exposid{current_} with \tcode{std::move(current)}. \end{itemdescr} -\indexlibrarymember{operator+}{transform_view::iterator}% +\indexlibraryctor{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(@\exposid{iterator}@ i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -friend constexpr @\exposid{iterator}@ operator+(difference_type n, @\exposid{iterator}@ i) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{outer-iterator}@(@\exposid{outer-iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return iterator\{*i.\exposid{parent_}, i.\exposid{current_} + n\};} +Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and +\exposid{current_} with \tcode{std::move(i.\exposid{current_})}. \end{itemdescr} -\indexlibrarymember{operator-}{transform_view::iterator}% +\indexlibrarymember{operator*}{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(@\exposid{iterator}@ i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr value_type operator*() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return iterator\{*i.\exposid{parent_}, i.\exposid{current_} - n\};} +Equivalent to: \tcode{return value_type\{*this\};} \end{itemdescr} -\indexlibrarymember{operator-}{transform_view::iterator}% +\indexlibrarymember{operator++}{lazy_split_view::\exposid{outer-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{outer-iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{current_};} -\end{itemdescr} - - -\rSec3[range.transform.sentinel]{Class template \tcode{transform_view::\exposid{sentinel}}} - -\indexlibraryglobal{transform_view::sentinel}% +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{copy_constructible}@ F> - requires @\libconcept{view}@ && is_object_v && - @\libconcept{regular_invocable}@> && - @\exposconcept{can-reference}@>> - template - class transform_view::@\exposid{sentinel}@ { - private: - using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos - 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}@ i) - 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}@& y, const @\exposid{iterator}@& x); - }; +const auto end = ranges::end(@\exposid{parent_}@->@\exposid{base_}@); +if (@\placeholder{current}@ == end) { + @\exposid{trailing_empty_}@ = false; + return *this; +} +const auto [pbegin, pend] = subrange{@\exposid{parent_}@->@\exposid{pattern_}@}; +if (pbegin == pend) ++@\placeholder{current}@; +else if constexpr (@\exposconcept{tiny-range}@) { + @\placeholder{current}@ = ranges::find(std::move(@\placeholder{current}@), end, *pbegin); + if (@\placeholder{current}@ != end) { + ++@\placeholder{current}@; + if (@\placeholder{current}@ == end) + @\exposid{trailing_empty_}@ = true; + } +} +else { + do { + auto [b, p] = ranges::mismatch(@\placeholder{current}@, end, pbegin, pend); + if (p == pend) { + @\placeholder{current}@ = b; + if (@\placeholder{current}@ == end) + @\exposid{trailing_empty_}@ = true; + break; // The pattern matched; skip it + } + } while (++@\placeholder{current}@ != end); } +return *this; \end{codeblock} +\end{itemdescr} -\indexlibraryctor{transform_view::sentinel}% +\indexlibrarymember{operator==}{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); +friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, const @\exposid{outer-iterator}@& y) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end}. +Equivalent to: +\begin{codeblock} +return x.@\exposid{current_}@ == y.@\exposid{current_}@ && x.@\exposid{trailing_empty_}@ == y.@\exposid{trailing_empty_}@; +\end{codeblock} \end{itemdescr} -\indexlibraryctor{transform_view::sentinel}% +\indexlibrarymember{operator==}{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. +Equivalent to: +\begin{codeblock} +return x.@\placeholdernc{current}@ == ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) && !x.@\exposid{trailing_empty_}@; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{base}{transform_view::sentinel} -\begin{itemdecl} -constexpr sentinel_t<@\exposid{Base}@> base() const; -\end{itemdecl} +\rSec3[range.lazy.split.outer.value]{Class \tcode{lazy_split_view::\exposid{outer-iterator}::value_type}} -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return \exposid{end_};} -\end{itemdescr} +\indexlibraryglobal{lazy_split_view::\exposid{outer-iterator}::value_type}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> + requires @\libconcept{view}@ && @\libconcept{view}@ && + @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && + (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) + template + struct lazy_split_view::@\exposid{outer-iterator}@::value_type + : view_interface { + private: + @\exposid{outer-iterator}@ @\exposid{i_}@ = @\exposid{outer-iterator}@(); // \expos + public: + value_type() = default; + constexpr explicit value_type(@\exposid{outer-iterator}@ i); -\indexlibrarymember{operator==}{transform_view::sentinel} + constexpr @\exposid{inner-iterator}@ begin() const; + constexpr default_sentinel_t end() const noexcept; + }; +} +\end{codeblock} + +\indexlibraryctor{lazy_split_view::\exposid{outer-iterator}::value_type}% \begin{itemdecl} -template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +constexpr explicit value_type(@\exposid{outer-iterator}@ i); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} +Initializes \exposid{i_} with \tcode{std::move(i)}. \end{itemdescr} -\indexlibrarymember{operator-}{transform_view::sentinel}% +\indexlibrarymember{begin}{lazy_split_view::\exposid{outer-iterator}::value_type}% \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{inner-iterator}@ begin() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{end_};} +Equivalent to: \tcode{return \exposid{inner-iterator}\{\exposid{i_}\};} \end{itemdescr} -\indexlibrarymember{operator-}{transform_view::sentinel}% +\indexlibrarymember{end}{lazy_split_view::\exposid{outer-iterator}::value_type}% \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_};} +Equivalent to: \tcode{return default_sentinel;} \end{itemdescr} -\rSec2[range.take]{Take view} - -\rSec3[range.take.overview]{Overview} - -\pnum -\tcode{take_view} produces a \libconcept{view} of the first $N$ elements -from another \libconcept{view}, or all the elements if the adapted -\libconcept{view} contains fewer than $N$. - -\pnum -\indexlibrarymember{take}{views}% -The name \tcode{views::take} denotes a -range adaptor object\iref{range.adaptor.object}. -Let \tcode{E} and \tcode{F} be expressions, -let \tcode{T} be \tcode{remove_cvref_t}, and -let \tcode{D} be \tcode{range_difference_t}. -If \tcode{decltype((F))} does not model -\tcode{\libconcept{convertible_to}}, -\tcode{views::take(E, F)} is ill-formed. -Otherwise, the expression \tcode{views::take(E, F)} -is expression-equivalent to: - -\begin{itemize} -\item -If \tcode{T} is a specialization -of \tcode{ranges::empty_view}\iref{range.empty.view}, -then \tcode{((void) F, \placeholdernc{decay-copy}(E))}, -except that the evaluations of \tcode{E} and \tcode{F} -are indeterminately sequenced. - -\item -Otherwise, if \tcode{T} models -\libconcept{random_access_range} and \libconcept{sized_range} -and is a specialization of -\tcode{span}\iref{views.span}, -\tcode{basic_string_view}\iref{string.view}, or -\tcode{ranges::subrange}\iref{range.subrange}, -then -\tcode{U(ranges::begin(E), -ranges::be\-gin(E) + std::min(ranges::distance(E), F))}, -except that \tcode{E} is evaluated only once, -where \tcode{U} is a type determined as follows: - -\begin{itemize} -\item if \tcode{T} is a specialization of \tcode{span}, -then \tcode{U} is \tcode{span}; -\item otherwise, if \tcode{T} is a specialization of \tcode{basic_string_view}, -then \tcode{U} is \tcode{T}; -\item otherwise, \tcode{T} is a specialization of \tcode{ranges::subrange}, and -\tcode{U} is \tcode{ranges::subrange>}; -\end{itemize} - -\item -otherwise, if \tcode{T} is -a specialization of \tcode{ranges::iota_view}\iref{range.iota.view} -that models \libconcept{random_access_range} and \libconcept{sized_range}, -then -\tcode{ranges::iota_view(*ranges::begin(E), -*(ranges::begin(E) + std::\linebreak{}min(ranges::distance(E), F)))}, -except that \tcode{E} is evaluated only once; - -\item -Otherwise, \tcode{ranges::take_view(E, F)}. -\end{itemize} - -\pnum -\begin{example} -\begin{codeblock} -vector is{0,1,2,3,4,5,6,7,8,9}; -for (int i : is | views::take(5)) - cout << i << ' '; // prints: 0 1 2 3 4 -\end{codeblock} -\end{example} - -\rSec3[range.take.view]{Class template \tcode{take_view}} +\rSec3[range.lazy.split.inner]{Class template \tcode{lazy_split_view::\exposid{inner-iterator}}} -\indexlibraryglobal{take_view}% -\indexlibrarymember{base}{take_view}% -\indexlibrarymember{begin}{take_view}% -\indexlibrarymember{end}{take_view}% -\indexlibrarymember{size}{take_view}% +\indexlibraryglobal{lazy_split_view::\exposid{inner-iterator}}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V> - class take_view : public view_interface> { + template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> + requires @\libconcept{view}@ && @\libconcept{view}@ && + @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && + (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) + template + struct lazy_split_view::@\exposid{inner-iterator}@ { private: - V @\exposid{base_}@ = V(); // \expos - range_difference_t @\exposid{count_}@ = 0; // \expos - - // \ref{range.take.sentinel}, class template \tcode{take_view::\exposid{sentinel}} - template struct @\exposid{sentinel}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + @\exposidnc{outer-iterator}@ @\exposid{i_}@ = @\exposidnc{outer-iterator}@(); // \expos + bool @\exposid{incremented_}@ = false; // \expos public: - take_view() requires @\libconcept{default_initializable}@ = default; - constexpr take_view(V base, range_difference_t count); + using iterator_concept = typename @\exposid{outer-iterator}@::iterator_concept; - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + using iterator_category = @\seebelownc@; // present only if \exposid{Base} + // models \libconcept{forward_range} + using value_type = range_value_t<@\exposid{Base}@>; + using difference_type = range_difference_t<@\exposid{Base}@>; - constexpr auto begin() requires (!@\exposconcept{simple-view}@) { - if constexpr (@\libconcept{sized_range}@) { - if constexpr (@\libconcept{random_access_range}@) { - return ranges::begin(@\exposid{base_}@); - } else { - auto sz = range_difference_t(size()); - return counted_iterator(ranges::begin(@\exposid{base_}@), sz); - } - } else { - return counted_iterator(ranges::begin(@\exposid{base_}@), @\exposid{count_}@); - } - } + @\exposid{inner-iterator}@() = default; + constexpr explicit @\exposid{inner-iterator}@(@\exposid{outer-iterator}@ i); - constexpr auto begin() const requires @\libconcept{range}@ { - if constexpr (@\libconcept{sized_range}@) { - if constexpr (@\libconcept{random_access_range}@) { - return ranges::begin(@\exposid{base_}@); - } else { - auto sz = range_difference_t(size()); - return counted_iterator(ranges::begin(@\exposid{base_}@), sz); - } - } else { - return counted_iterator(ranges::begin(@\exposid{base_}@), @\exposid{count_}@); - } - } + constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; + constexpr iterator_t<@\exposid{Base}@> base() && requires @\libconcept{forward_range}@; - constexpr auto end() requires (!@\exposconcept{simple-view}@) { - if constexpr (@\libconcept{sized_range}@) { - if constexpr (@\libconcept{random_access_range}@) - return ranges::begin(@\exposid{base_}@) + range_difference_t(size()); - else - return default_sentinel; - } else { - return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; - } - } + constexpr decltype(auto) operator*() const { return *@\exposid{i_}@.@\placeholder{current}@; } - constexpr auto end() const requires @\libconcept{range}@ { - if constexpr (@\libconcept{sized_range}@) { - if constexpr (@\libconcept{random_access_range}@) - return ranges::begin(@\exposid{base_}@) + range_difference_t(size()); - else - return default_sentinel; - } else { - return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; - } + constexpr @\exposid{inner-iterator}@& operator++(); + constexpr decltype(auto) operator++(int) { + if constexpr (@\libconcept{forward_range}@<@\exposid{Base}@>) { + auto tmp = *this; + ++*this; + return tmp; + } else + ++*this; } - constexpr auto size() requires @\libconcept{sized_range}@ { - auto n = ranges::size(@\exposid{base_}@); - return ranges::min(n, static_cast(@\exposid{count_}@)); + friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; + + friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); + + friend constexpr decltype(auto) iter_move(const @\exposid{inner-iterator}@& i) + noexcept(noexcept(ranges::iter_move(i.@\exposid{i_}@.@\placeholdernc{current}@))) { + return ranges::iter_move(i.@\exposid{i_}@.@\placeholdernc{current}@); } - constexpr auto size() const requires @\libconcept{sized_range}@ { - auto n = ranges::size(@\exposid{base_}@); - return ranges::min(n, static_cast(@\exposid{count_}@)); - } + friend constexpr void iter_swap(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{i_}@.@\placeholdernc{current}@, y.@\exposid{i_}@.@\placeholdernc{current}@))) + requires @\libconcept{indirectly_swappable}@>; }; - - template - take_view(R&&, range_difference_t) - -> take_view>; } \end{codeblock} -\indexlibraryctor{take_view}% +\pnum +If \exposid{Base} does not model \libconcept{forward_range} +there is no member \tcode{iterator_category}. +Otherwise, the \grammarterm{typedef-name} \tcode{iterator_category} denotes: +\begin{itemize} +\item +\tcode{forward_iterator_tag} if +\tcode{iterator_traits>::iterator_category} models \linebreak +\tcode{\libconcept{derived_from}}; +\item otherwise, \tcode{iterator_traits>::iterator_category}. +\end{itemize} + +\indexlibraryctor{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr take_view(V base, range_difference_t count); +constexpr explicit @\exposid{inner-iterator}@(@\exposid{outer-iterator}@ i); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{count_} with \tcode{count}. +Initializes \exposid{i_} with \tcode{std::move(i)}. \end{itemdescr} -\rSec3[range.take.sentinel]{Class template \tcode{take_view::\exposid{sentinel}}} - -\indexlibraryglobal{take_view::sentinel}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - template - class take_view::@\exposid{sentinel}@ { - private: - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos - template - using @\exposid{CI}@ = counted_iterator>>; // \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}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +\indexlibrarymember{base}{lazy_split_view::\exposid{inner-iterator}}% +\begin{itemdecl} +constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +\end{itemdecl} - constexpr sentinel_t<@\exposid{Base}@> base() const; +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{i_}.\placeholder{current};} +\end{itemdescr} - friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); +\indexlibrarymember{base}{lazy_split_view::\exposid{inner-iterator}}% +\begin{itemdecl} +constexpr iterator_t<@\exposid{Base}@> base() && requires @\libconcept{forward_range}@; +\end{itemdecl} - template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); - }; -} -\end{codeblock} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return std::move(\exposid{i_}.\placeholder{current});} +\end{itemdescr} -\indexlibraryctor{take_view::sentinel}% +\indexlibrarymember{operator++}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); +constexpr @\exposid{inner-iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end}. +Equivalent to: +\begin{codeblock} +@\exposid{incremented_}@ = true; +if constexpr (!@\libconcept{forward_range}@<@\exposid{Base}@>) { + if constexpr (Pattern::size() == 0) { + return *this; + } +} +++@\exposid{i_}@.@\placeholder{current}@; +return *this; +\end{codeblock} \end{itemdescr} -\indexlibraryctor{take_view::sentinel}% +\indexlibrarymember{operator==}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) + requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{std::move(s.\exposid{end_})}. +Equivalent to: \tcode{return x.\exposid{i_}.\placeholder{current} == y.\exposid{i_}.\placeholder{current};} \end{itemdescr} -\indexlibrarymember{base}{take_view::sentinel}% +\indexlibrarymember{operator==}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr sentinel_t<@\exposid{Base}@> base() const; +friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{end_};} +Equivalent to: +\begin{codeblock} +auto [pcur, pend] = subrange{x.@\exposid{i_}@.@\exposid{parent_}@->@\exposid{pattern_}@}; +auto end = ranges::end(x.@\exposid{i_}@.@\exposid{parent_}@->@\exposid{base_}@); +if constexpr (@\exposconcept{tiny-range}@) { + const auto & cur = x.@\exposid{i_}@.@\placeholder{current}@; + if (cur == end) return true; + if (pcur == pend) return x.@\exposid{incremented_}@; + return *cur == *pcur; +} else { + auto cur = x.@\exposid{i_}@.@\placeholder{current}@; + if (cur == end) return true; + if (pcur == pend) return x.@\exposid{incremented_}@; + do { + if (*cur != *pcur) return false; + if (++pcur == pend) return true; + } while (++cur != end); + return false; +} +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator==}{take_view::sentinel}% +\indexlibrarymember{iter_swap}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); - -template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr bool operator==(const @\exposid{CI}@& y, const @\exposid{sentinel}@& x); +friend constexpr void iter_swap(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) + noexcept(noexcept(ranges::iter_swap(x.@\exposid{i_}@.@\placeholdernc{current}@, y.@\exposid{i_}@.@\placeholdernc{current}@))) + requires @\libconcept{indirectly_swappable}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return y.count() == 0 || y.base() == x.\exposid{end_};} +Equivalent to +\tcode{ranges::iter_swap(x.\exposid{i_}.\placeholdernc{current}, y.\exposid{i_}.\placeholdernc{current})}. \end{itemdescr} -\rSec2[range.take.while]{Take while view} +\rSec2[range.split]{Split view} -\rSec3[range.take.while.overview]{Overview} +\rSec3[range.split.overview]{Overview} \pnum -Given a unary predicate \tcode{pred} and a \libconcept{view} \tcode{r}, -\tcode{take_while_view} produces a \libconcept{view} -of the range \range{begin(r)}{ranges::find_if_not(r, pred)}. +\tcode{split_view} takes a \libconcept{view} and a delimiter, and +splits the \libconcept{view} into \tcode{subrange}s on the delimiter. +The delimiter can be a single element or a \libconcept{view} of elements. -\indexlibraryglobal{take_while}% \pnum -\indexlibrarymember{take_while}{views}% -The name \tcode{views::take_while} denotes +The name \tcode{views::split} denotes a range adaptor object\iref{range.adaptor.object}. Given subexpressions \tcode{E} and \tcode{F}, -the expression \tcode{views::take_while(E, F)} -is expression-equivalent to \tcode{take_while_view(E, F)}. +the expression \tcode{views::split(E, F)} is expression-equivalent to +\tcode{split_view(E, F)}. \pnum \begin{example} \begin{codeblock} -auto input = istringstream{"0 1 2 3 4 5 6 7 8 9"}; -auto small = [](const auto x) noexcept { return x < 5; }; -auto small_ints = istream_view(input) | views::take_while(small); -for (const auto i : small_ints) { - cout << i << ' '; // prints \tcode{0 1 2 3 4} +string str{"the quick brown fox"}; +for (string_view word : views::split(str, ' ')) { + cout << word << '*'; } -auto i = 0; -input >> i; -cout << i; // prints \tcode{6} +// The above prints \tcode{the*quick*brown*fox*} \end{codeblock} \end{example} -\rSec3[range.take.while.view]{Class template \tcode{take_while_view}} +\rSec3[range.split.view]{Class template \tcode{split_view}} -\indexlibraryglobal{take_while_view}% -\indexlibrarymember{base}{take_while_view}% -\indexlibrarymember{begin}{take_while_view}% -\indexlibrarymember{end}{take_while_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V, class Pred> - requires @\libconcept{input_range}@ && is_object_v && - @\libconcept{indirect_unary_predicate}@> - class take_while_view : public view_interface> { - // \ref{range.take.while.sentinel}, class template \tcode{take_while_view::\exposid{sentinel}} - template class @\exposidnc{sentinel}@; // \expos + 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 : public view_interface> { + private: + V @\exposid{base_}@ = V(); // \expos + Pattern @\exposid{pattern_}@ = Pattern(); // \expos - V @\exposid{base_}@ = V(); // \expos - @\exposidnc{copyable-box}@ @\exposid{pred_}@; // \expos + // \ref{range.split.iterator}, class \tcode{split_view::\exposid{iterator}} + struct @\exposid{iterator}@; // \expos + + // \ref{range.split.sentinel}, class \tcode{split_view::\exposid{sentinel}} + struct @\exposid{sentinel}@; // \expos public: - take_while_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr take_while_view(V base, Pred pred); + split_view() + requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr split_view(V base, Pattern pattern); + + template<@\libconcept{forward_range}@ R> + requires @\libconcept{constructible_from}@> && + @\libconcept{constructible_from}@>> + constexpr split_view(R&& r, range_value_t e); 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 auto begin() requires (!@\exposconcept{simple-view}@) - { return ranges::begin(@\exposid{base_}@); } - - constexpr auto begin() const - requires @\libconcept{range}@ && - @\libconcept{indirect_unary_predicate}@> - { return ranges::begin(@\exposid{base_}@); } + constexpr @\exposid{iterator}@ begin(); - constexpr auto end() requires (!@\exposconcept{simple-view}@) - { return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@), addressof(*@\exposid{pred_}@)); } + constexpr auto end() { + if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@), {}}; + } else { + return @\exposid{sentinel}@{*this}; + } + } - constexpr auto end() const - requires @\libconcept{range}@ && - @\libconcept{indirect_unary_predicate}@> - { return @\exposid{sentinel}@(ranges::end(@\exposid{base_}@), addressof(*@\exposid{pred_}@)); } + constexpr subrange> @\exposid{find-next}@(iterator_t); // \expos }; - template - take_while_view(R&&, Pred) -> take_while_view, Pred>; + template + split_view(R&&, P&&) -> split_view, views::all_t

>; + + template<@\libconcept{forward_range}@ R> + split_view(R&&, range_value_t) + -> split_view, single_view>>; } \end{codeblock} -\indexlibraryctor{take_while_view}% \begin{itemdecl} -constexpr take_while_view(V base, Pred pred); +constexpr split_view(V base, Pattern pattern); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)}, and +\exposid{pattern_} with \tcode{std::move(pattern)}. +\end{itemdescr} + +\indexlibraryctor{split_view}% +\begin{itemdecl} +template<@\libconcept{forward_range}@ R> + requires @\libconcept{constructible_from}@> && + @\libconcept{constructible_from}@>> +constexpr split_view(R&& r, range_value_t e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{base_} with \tcode{views::all(std::forward(r))}, and +\exposid{pattern_} with \tcode{views::\linebreak single(std::move(e))}. +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{iterator}@ begin(); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{pred_} with \tcode{std::move(pred)}. +\returns +\tcode{\{*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{split_view} +for use on subsequent calls. \end{itemdescr} -\indexlibrarymember{pred}{take_while_view}% \begin{itemdecl} -constexpr const Pred& pred() const; +constexpr subrange> @\exposid{find-next}@(iterator_t it); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *\exposid{pred_};} +Equivalent to: +\begin{codeblock} +auto [b, e] = ranges::search(subrange(it, ranges::end(@\exposid{base_}@)), @\exposid{pattern_}@); +if (b != ranges::end(@\exposid{base_}@) && ranges::empty(@\exposid{pattern_}@)) { + ++b; + ++e; +} +return {b, e}; +\end{codeblock} \end{itemdescr} -\rSec3[range.take.while.sentinel]{Class template \tcode{take_while_view::\exposid{sentinel}}} +\rSec3[range.split.iterator]{Class \tcode{split_view::\exposid{iterator}}} -\indexlibraryglobal{take_while_view::sentinel}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V, class Pred> - requires @\libconcept{input_range}@ && is_object_v && - @\libconcept{indirect_unary_predicate}@> - template - class take_while_view::@\exposidnc{sentinel}@ { - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - - sentinel_t<@\exposidnc{Base}@> @\exposid{end_}@ = sentinel_t<@\exposidnc{Base}@>(); // \expos - const Pred* @\exposid{pred_}@ = nullptr; // \expos + 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::@\exposid{iterator}@ { + private: + split_view* @\exposid{parent_}@ = nullptr; // \expos + iterator_t @\exposid{cur_}@ = iterator_t(); // \expos + subrange> @\exposid{next_}@ = subrange>(); // \expos + bool @\exposid{trailing_empty_}@ = false; // \expos public: - @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end, const Pred* pred); - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + using iterator_concept = forward_iterator_tag; + using iterator_category = input_iterator_tag; + using value_type = subrange>; + using difference_type = range_difference_t; - constexpr sentinel_t<@\exposid{Base}@> base() const { return @\exposid{end_}@; } + @\exposid{iterator}@() = default; + constexpr @\exposid{iterator}@(split_view& parent, iterator_t current, subrange> next); - friend constexpr bool operator==(const iterator_t<@\exposid{Base}@>& x, const @\exposid{sentinel}@& y); + constexpr iterator_t base() const; + constexpr value_type operator*() const; - template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr bool operator==(const iterator_t<@\exposid{maybe-const}@>& x, - const @\exposid{sentinel}@& y); + constexpr @\exposid{iterator}@& operator++(); + constexpr @\exposid{iterator}@ operator++(int); + + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); }; } \end{codeblock} -\indexlibraryctor{take_while_view::sentinel}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end, const Pred* pred); +constexpr @\exposid{iterator}@(split_view& parent, iterator_t current, subrange> next); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end} and \exposid{pred_} with \tcode{pred}. +Initializes \exposid{parent_} with \tcode{addressof(parent)}, +\exposid{cur_} with \tcode{std::move(current)}, and +\exposid{next_} with \tcode{std::move(next)}. \end{itemdescr} -\indexlibraryctor{take_while_view::sentinel}% \begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +constexpr iterator_t base() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{s.\exposid{end_}} and -\exposid{pred_} with \tcode{s.\exposid{pred_}}. +Equivalent to \tcode{return \exposid{cur_};} \end{itemdescr} -\indexlibrarymember{operator==}{take_while_view::sentinel}% \begin{itemdecl} -friend constexpr bool operator==(const iterator_t<@\exposid{Base}@>& x, const @\exposid{sentinel}@& y); - -template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr bool operator==(const iterator_t<@\exposid{maybe-const}@>& x, - const @\exposid{sentinel}@& y); +constexpr value_type operator*() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return y.\exposid{end_} == x || !invoke(*y.\exposid{pred_}, *x);} +Equivalent to \tcode{return \{\exposid{cur_}, \exposid{next_}.begin()\};} \end{itemdescr} -\rSec2[range.drop]{Drop view} - -\rSec3[range.drop.overview]{Overview} - -\pnum -\tcode{drop_view} produces a \libconcept{view} -excluding the first $N$ elements from another \libconcept{view}, or -an empty range if the adapted \libconcept{view} contains fewer than $N$ elements. +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} +\begin{itemdescr} \pnum -\indexlibrarymember{drop}{views}% -The name \tcode{views::drop} denotes -a range adaptor object\iref{range.adaptor.object}. -Let \tcode{E} and \tcode{F} be expressions, -let \tcode{T} be \tcode{remove_cvref_t}, and -let \tcode{D} be \tcode{range_difference_t}. -If \tcode{decltype((F))} does not model -\tcode{\libconcept{convertible_to}}, -\tcode{views::drop(E, F)} is ill-formed. -Otherwise, the expression \tcode{views::drop(E, F)} -is expression-equivalent to: - -\begin{itemize} -\item -If \tcode{T} is a specialization of -\tcode{ranges::empty_view}\iref{range.empty.view}, -then \tcode{((void) F, \placeholdernc{decay-copy}(E))}, -except that the evaluations of \tcode{E} and \tcode{F} -are indeterminately sequenced. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{cur_}@ = @\exposid{next_}@.begin(); +if (@\exposid{cur_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { + @\exposid{cur_}@ = @\exposid{next_}@.end(); + if (@\exposid{cur_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { + @\exposid{trailing_empty_}@ = true; + @\exposid{next_}@ = {@\exposid{cur_}@, @\exposid{cur_}@}; + } else { + @\exposid{next_}@ = @\exposid{parent_}@->@\exposid{find-next}@(@\exposid{cur_}@); + } +} else { + @\exposid{trailing_empty_}@ = false; +} +return *this; +\end{codeblock} +\end{itemdescr} -\item -Otherwise, if \tcode{T} models -\libconcept{random_access_range} and \libconcept{sized_range} -and is -\begin{itemize} -\item a specialization of \tcode{span}\iref{views.span}, -\item a specialization of \tcode{basic_string_view}\iref{string.view}, -\item a specialization of \tcode{ranges::iota_view}\iref{range.iota.view}, or -\item a specialization of \tcode{ranges::subrange}\iref{range.subrange} -where \tcode{T::\exposid{StoreSize}} is \tcode{false}, -\end{itemize} -then \tcode{U(ranges::begin(E) + std::min(ranges::distance(E), F), ranges::end(E))}, -except that \tcode{E} is evaluated only once, -where \tcode{U} is \tcode{span} -if \tcode{T} is a specialization of \tcode{span} and \tcode{T} otherwise. +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int); +\end{itemdecl} -\item -Otherwise, -if \tcode{T} is -a specialization of \tcode{ranges::subrange}\iref{range.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), -\exposid{to-unsigned-like}(ranges::distance(E) - -std::min(ranges::distance(E), F)))}, -except that \tcode{E} and \tcode{F} are each evaluated only once. +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} -\item -Otherwise, \tcode{ranges::drop_view(E, F)}. -\end{itemize} +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{example} +\effects +Equivalent to: \begin{codeblock} -auto ints = views::iota(0) | views::take(10); -for (auto i : ints | views::drop(5)) { - cout << i << ' '; // prints \tcode{5 6 7 8 9} -} +return x.@\exposid{cur_}@ == y.@\exposid{cur_}@ && x.@\exposid{trailing_empty_}@ == y.@\exposid{trailing_empty_}@; \end{codeblock} -\end{example} +\end{itemdescr} -\rSec3[range.drop.view]{Class template \tcode{drop_view}} +\rSec3[range.split.sentinel]{Class \tcode{split_view::\exposid{sentinel}}} -\indexlibraryglobal{drop_view}% -\indexlibrarymember{base}{drop_view}% -\indexlibrarymember{end}{drop_view}% -\indexlibrarymember{size}{drop_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V> - class drop_view : public view_interface> { - public: - drop_view() requires @\libconcept{default_initializable}@ = default; - constexpr drop_view(V base, range_difference_t count); - - 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}@ && - @\libconcept{random_access_range}@ && @\libconcept{sized_range}@)); - constexpr auto begin() const - requires @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; - - constexpr auto end() requires (!@\exposconcept{simple-view}@) - { return ranges::end(@\exposid{base_}@); } - - constexpr auto end() const requires @\libconcept{range}@ - { return ranges::end(@\exposid{base_}@); } - - constexpr auto size() requires @\libconcept{sized_range}@ { - const auto s = ranges::size(@\exposid{base_}@); - const auto c = static_cast(@\exposid{count_}@); - return s < c ? 0 : s - c; - } + template<@\libconcept{forward_range}@ V, @\libconcept{forward_range}@ Pattern> + requires @\libconcept{view}@ && @\libconcept{view}@ && + @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> + struct split_view::@\exposid{sentinel}@ { + private: + sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos - constexpr auto size() const requires @\libconcept{sized_range}@ { - const auto s = ranges::size(@\exposid{base_}@); - const auto c = static_cast(@\exposid{count_}@); - return s < c ? 0 : s - c; - } + public: + @\exposid{sentinel}@() = default; + constexpr explicit @\exposid{sentinel}@(split_view& parent); - private: - V @\exposid{base_}@ = V(); // \expos - range_difference_t @\exposid{count_}@ = 0; // \expos + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); }; - - template - drop_view(R&&, range_difference_t) -> drop_view>; } \end{codeblock} -\indexlibraryctor{drop_view}% \begin{itemdecl} -constexpr drop_view(V base, range_difference_t count); +constexpr explicit @\exposid{sentinel}@(split_view& parent); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{count >= 0} is \tcode{true}. - \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{count_} with \tcode{count}. +Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. \end{itemdescr} -\indexlibrarymember{begin}{drop_view}% \begin{itemdecl} -constexpr auto begin() - requires (!(@\exposconcept{simple-view}@ && - @\libconcept{random_access_range}@ && @\libconcept{sized_range}@)); -constexpr auto begin() const - requires @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{ranges::next(ranges::begin(\exposid{base_}), \exposid{count_}, ranges::end(\exposid{base_}))}. +\effects +Equivalent to: \tcode{return x.\exposid{cur_} == y.\exposid{end_} \&\& !x.\exposid{trailing_empty_};} +\end{itemdescr} + +\rSec2[range.counted]{Counted view} \pnum -\remarks -In order to provide the amortized constant-time complexity required -by the \libconcept{range} concept -when \tcode{drop_view} models \libconcept{forward_range}, -the first overload caches the result within the \tcode{drop_view} -for use on subsequent calls. +\indextext{range!counted}% +A counted view presents a \libconcept{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} -Without this, -applying a \tcode{reverse_view} over a \tcode{drop_view} -would have quadratic iteration complexity. +This case can result in substitution failure +when \tcode{views::counted(E, F)} +appears in the immediate context of a template instantiation. \end{note} -\end{itemdescr} +Otherwise, \tcode{views::counted(E, F)} +is expression-equivalent to: -\rSec2[range.drop.while]{Drop while view} +\begin{itemize} +\item +If \tcode{T} models \libconcept{contiguous_iterator}, +then \tcode{span(to_address(E), static_cast(static_-\linebreak{}cast(F)))}. -\rSec3[range.drop.while.overview]{Overview} +\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} \pnum -Given a unary predicate \tcode{pred} and a \libconcept{view} \tcode{r}, -\tcode{drop_while_view} produces a \libconcept{view} -of the range \range{ranges::find_if_not(r, pred)}{ranges::end(r)}. +\tcode{common_view} takes a \libconcept{view} which has different types for +its iterator and sentinel and turns it into a \libconcept{view} of the same +elements with an iterator and sentinel of the same type. \pnum -\indexlibrarymember{drop_while}{views}% -The name \tcode{views::drop_while} -denotes a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{F}, -the expression \tcode{views::drop_while(E, F)} -is expression-equivalent to \tcode{drop_while_view(E, F)}. +\begin{note} +\tcode{common_view} is useful for calling legacy algorithms that expect +a range's iterator and sentinel types to be the same. +\end{note} + +\pnum +\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. + +\item Otherwise, \tcode{common_view\{E\}}. +\end{itemize} \pnum \begin{example} \begin{codeblock} -constexpr auto source = " \t \t \t hello there"; -auto is_invisible = [](const auto x) { return x == ' ' || x == '\t'; }; -auto skip_ws = views::drop_while(source, is_invisible); -for (auto c : skip_ws) { - cout << c; // prints \tcode{hello there} with no leading space +// 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()); + // ... } \end{codeblock} \end{example} -\rSec3[range.drop.while.view]{Class template \tcode{drop_while_view}} +\rSec3[range.common.view]{Class template \tcode{common_view}} -\indexlibraryglobal{drop_while_view}% -\indexlibrarymember{base}{drop_while_view}% -\indexlibrarymember{end}{drop_while_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{view}@ V, class Pred> - requires @\libconcept{input_range}@ && is_object_v && - @\libconcept{indirect_unary_predicate}@> - class drop_while_view : public view_interface> { + template<@\libconcept{view}@ V> + requires (!@\libconcept{common_range}@ && @\libconcept{copyable}@>) + class common_view : public view_interface> { + private: + V @\exposid{base_}@ = V(); // \expos public: - drop_while_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr drop_while_view(V base, Pred pred); + common_view() requires @\libconcept{default_initializable}@ = default; + + constexpr explicit common_view(V r); 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 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_}@)); + } - constexpr auto begin(); + 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() { return ranges::end(@\exposid{base_}@); } + constexpr auto end() { + if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) + return ranges::begin(@\exposid{base_}@) + ranges::size(@\exposid{base_}@); + else + return common_iterator, sentinel_t>(ranges::end(@\exposid{base_}@)); + } - private: - V @\exposid{base_}@ = V(); // \expos - @\placeholder{copyable-box}@ @\exposid{pred_}@; @\itcorr[-1]@ // \expos + constexpr auto end() const requires @\libconcept{range}@ { + if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) + return ranges::begin(@\exposid{base_}@) + ranges::size(@\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_}@); + } }; - template - drop_while_view(R&&, Pred) -> drop_while_view, Pred>; + template + common_view(R&&) -> common_view>; } \end{codeblock} -\indexlibraryctor{drop_while_view}% -\begin{itemdecl} -constexpr drop_while_view(V base, Pred pred); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{pred_} with \tcode{std::move(pred)}. -\end{itemdescr} - -\indexlibrarymember{pred}{drop_while_view}% +\indexlibraryctor{common_view}% \begin{itemdecl} -constexpr const Pred& pred() const; +constexpr explicit common_view(V base); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *\exposid{pred_};} -\end{itemdescr} - -\indexlibrarymember{begin}{drop_while_view}% -\begin{itemdecl} -constexpr auto begin(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{\exposid{pred_}.has_value()} is \tcode{true}. - -\pnum -\returns -\tcode{ranges::find_if_not(\exposid{base_}, cref(*\exposid{pred_}))}. - -\pnum -\remarks -In order to provide the amortized constant-time complexity -required by the \libconcept{range} concept -when \tcode{drop_while_view} models \libconcept{forward_range}, -the first call caches the result within the \tcode{drop_while_view} -for use on subsequent calls. -\begin{note} -Without this, -applying a \tcode{reverse_view} over a \tcode{drop_while_view} -would have quadratic iteration complexity. -\end{note} +Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\rSec2[range.join]{Join view} +\rSec2[range.reverse]{Reverse view} -\rSec3[range.join.overview]{Overview} +\rSec3[range.reverse.overview]{Overview} \pnum -\tcode{join_view} flattens a \libconcept{view} of ranges into a -\libconcept{view}. +\tcode{reverse_view} takes a bidirectional \libconcept{view} and produces +another \libconcept{view} that iterates the same elements in reverse order. \pnum -\indexlibrarymember{join}{views}% -The name \tcode{views::join} denotes a +\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::join(E)} is expression-equivalent to -\tcode{join_view>\{E\}}. +\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: +\begin{codeblock} +subrange(E.end().base(), E.begin().base()) +\end{codeblock} + \end{itemize} + However, in either case \tcode{E} is evaluated only once. +\item + Otherwise, equivalent to \tcode{reverse_view\{E\}}. +\end{itemize} \pnum \begin{example} \begin{codeblock} -vector ss{"hello", " ", "world", "!"}; -for (char ch : ss | views::join) - cout << ch; // prints: \tcode{hello world!} +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.join.view]{Class template \tcode{join_view}} +\rSec3[range.reverse.view]{Class template \tcode{reverse_view}} -\indexlibraryglobal{join_view}% -\indexlibrarymember{base}{join_view}% -\indexlibrarymember{begin}{join_view}% -\indexlibrarymember{end}{join_view}% +\indexlibraryglobal{reverse_view}% +\indexlibrarymember{base}{reverse_view}% +\indexlibrarymember{size}{reverse_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ V> - requires @\libconcept{view}@ && @\libconcept{input_range}@> - class join_view : public view_interface> { + template<@\libconcept{view}@ V> + requires @\libconcept{bidirectional_range}@ + class reverse_view : public view_interface> { private: - using @\exposidnc{InnerRng}@ = range_reference_t; // \expos - - // \ref{range.join.iterator}, class template \tcode{join_view::\exposid{iterator}} - template - struct @\exposidnc{iterator}@; // \expos - - // \ref{range.join.sentinel}, class template \tcode{join_view::\exposid{sentinel}} - template - struct @\exposidnc{sentinel}@; // \expos - - V @\exposid{base_}@ = V(); // \expos - - @\exposidnc{non-propagating-cache}@> @\exposid{inner_}@; // \expos, present only - // when \tcode{!is_reference_v<\exposid{InnerRng}>} - + V @\exposid{base_}@ = V(); // \expos public: - join_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit join_view(V base); + 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 auto begin() { - constexpr bool use_const = @\exposconcept{simple-view}@ && - is_reference_v>; - return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; - } + constexpr reverse_iterator> begin(); + constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; + constexpr auto begin() const requires @\libconcept{common_range}@; - constexpr auto begin() const - requires @\libconcept{input_range}@ && - is_reference_v> - { return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; } + constexpr reverse_iterator> end(); + constexpr auto end() const requires @\libconcept{common_range}@; - constexpr auto end() { - if constexpr (@\libconcept{forward_range}@ && - is_reference_v<@\exposid{InnerRng}@> && @\libconcept{forward_range}@<@\exposid{InnerRng}@> && - @\libconcept{common_range}@ && @\libconcept{common_range}@<@\exposid{InnerRng}@>) - return @\exposid{iterator}@<@\exposconcept{simple-view}@>{*this, ranges::end(@\exposid{base_}@)}; - else - return @\exposid{sentinel}@<@\exposconcept{simple-view}@>{*this}; + constexpr auto size() requires @\libconcept{sized_range}@ { + return ranges::size(@\exposid{base_}@); } - constexpr auto end() const - requires @\libconcept{input_range}@ && - is_reference_v> { - if constexpr (@\libconcept{forward_range}@ && - @\libconcept{forward_range}@> && - @\libconcept{common_range}@ && - @\libconcept{common_range}@>) - return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; - else - return @\exposid{sentinel}@{*this}; + constexpr auto size() const requires @\libconcept{sized_range}@ { + return ranges::size(@\exposid{base_}@); } }; template - explicit join_view(R&&) -> join_view>; + reverse_view(R&&) -> reverse_view>; } \end{codeblock} -\indexlibraryctor{join_view}% +\indexlibraryctor{reverse_view}% \begin{itemdecl} -constexpr explicit join_view(V base); +constexpr explicit reverse_view(V base); \end{itemdecl} \begin{itemdescr} @@ -5729,283 +8567,388 @@ Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\rSec3[range.join.iterator]{Class template \tcode{join_view::\exposid{iterator}}} +\indexlibrarymember{begin}{reverse_view}% +\begin{itemdecl} +constexpr reverse_iterator> begin(); +\end{itemdecl} -\indexlibraryglobal{join_view::iterator}% +\begin{itemdescr} +\pnum +\returns \begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V> - requires @\libconcept{view}@ && @\libconcept{input_range}@> - template - struct join_view::@\exposid{iterator}@ { - private: - using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - using @\exposidnc{OuterIter}@ = iterator_t<@\exposidnc{Base}@>; // \expos - using @\exposidnc{InnerIter}@ = iterator_t>; // \expos - - static constexpr bool @\exposidnc{ref-is-glvalue}@ = // \expos - is_reference_v>; - - @\exposidnc{OuterIter}@ @\exposid{outer_}@ = @\exposidnc{OuterIter}@(); // \expos - @\exposidnc{InnerIter}@ @\exposid{inner_}@ = @\exposidnc{InnerIter}@(); // \expos - @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos - - constexpr void @\exposidnc{satisfy}@(); // \expos - - public: - using iterator_concept = @\seebelow@; - using iterator_category = @\seebelow@; // not always present - using value_type = range_value_t>; - using difference_type = @\seebelow@; - - @\exposid{iterator}@() requires @\libconcept{default_initializable}@<@\exposid{OuterIter}@> && - @\itcorr[-2]\libconcept{default_initializable}@<@\exposid{InnerIter}@> = default; - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer); - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && - @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && - @\libconcept{convertible_to}@, @\exposid{InnerIter}@>; - - constexpr decltype(auto) operator*() const { return *@\exposid{inner_}@; } +make_reverse_iterator(ranges::next(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@))) +\end{codeblock} - constexpr @\exposid{InnerIter}@ operator->() const - requires @\exposconcept{has-arrow}@<@\exposid{InnerIter}@> && @\libconcept{copyable}@<@\exposid{InnerIter}@>; +\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} - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && - @\libconcept{forward_range}@>; +\indexlibrarymember{begin}{reverse_view}% +\begin{itemdecl} +constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; +constexpr auto begin() const requires @\libconcept{common_range}@; +\end{itemdecl} - constexpr @\exposid{iterator}@& operator--() - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\libconcept{bidirectional_range}@> && - @\libconcept{common_range}@>; +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return make_reverse_iterator(ranges::end(\exposid{base_}));} +\end{itemdescr} - constexpr @\exposid{iterator}@ operator--(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\libconcept{bidirectional_range}@> && - @\libconcept{common_range}@>; +\indexlibrarymember{end}{reverse_view}% +\begin{itemdecl} +constexpr reverse_iterator> end(); +constexpr auto end() const requires @\libconcept{common_range}@; +\end{itemdecl} - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@> && - @\libconcept{equality_comparable}@>>; +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return make_reverse_iterator(ranges::begin(\exposid{base_}));} +\end{itemdescr} - friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& i) - noexcept(noexcept(ranges::iter_move(i.@\exposid{inner_}@))) { - return ranges::iter_move(i.@\exposid{inner_}@); - } +\rSec2[range.as.const]{As const view} - friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - noexcept(noexcept(ranges::iter_swap(x.@\exposid{inner_}@, y.@\exposid{inner_}@))) - requires @\libconcept{indirectly_swappable}@<@\exposid{InnerIter}@>; - }; -} -\end{codeblock} +\rSec3[range.as.const.overview]{Overview} \pnum -\tcode{iterator::iterator_concept} is defined as follows: -\begin{itemize} -\item If \exposid{ref-is-glvalue} is \tcode{true}, - \exposid{Base} models \libconcept{bidirectional_range}, and - \tcode{range_reference_t<\exposid{Base}>} models - both \libconcept{bidirectional_range} and \libconcept{common_range}, - then \tcode{iterator_concept} denotes \tcode{bidirectio\-nal_iterator_tag}. -\item Otherwise, if \exposid{ref-is-glvalue} is \tcode{true} and - \exposid{Base} and \tcode{range_reference_t<\exposid{Base}>} - each model \libconceptx{for\-ward_range}{forward_range}, then \tcode{iterator_concept} denotes - \tcode{forward_iterator_tag}. -\item Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. -\end{itemize} +\tcode{as_const_view} presents a \libconcept{view} of an underlying sequence as constant. +That is, the elements of an \tcode{as_const_view} cannot be modified. \pnum -The member \grammarterm{typedef-name} \tcode{iterator_category} is defined -if and only if \exposid{ref-is-glvalue} is \tcode{true}, -\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: +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 Let \placeholder{OUTERC} denote - \tcode{iterator_traits>::iterator_category}, and - let \placeholder{INNERC} denote - \tcode{iterator_traits>>::iterator_category}. -\item If - \placeholder{OUTERC} and \placeholder{INNERC} each model - \tcode{\libconcept{derived_from}} and - \tcode{range_reference_t<\exposid{Base}>} models \libconcept{common_range}, - \tcode{iterator_category} denotes \tcode{bidirectional_iterator_tag}. -\item Otherwise, if - \placeholder{OUTERC} and \placeholder{INNERC} each model - \tcode{\libconcept{derived_from}}, \tcode{iter\-ator_category} - denotes \tcode{forward_iterator_tag}. -\item Otherwise, - \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\item +If \tcode{views::all_t} models \libconcept{constant_range}, +then \tcode{views::all(E)}. +\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{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 -\tcode{iterator::difference_type} denotes the type: +\begin{example} \begin{codeblock} -common_type_t< - range_difference_t<@\exposid{Base}@>, - range_difference_t>> -\end{codeblock} +template +void cant_touch_this(R&&); -\pnum -\tcode{join_view} iterators use the \exposid{satisfy} function to skip over -empty inner ranges. +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} -\begin{itemdecl} -constexpr void @\exposid{satisfy}@(); // \expos -\end{itemdecl} +\rSec3[range.as.const.view]{Class template \tcode{as_const_view}} -\begin{itemdescr} -\pnum -\effects -Equivalent to: \begin{codeblock} -auto update_inner = [this](const iterator_t<@\exposid{Base}@>& x) -> auto&& { - if constexpr (@\exposid{ref-is-glvalue}@) // \tcode{*x} is a reference - return *x; - else - return @\exposid{parent_}@->@\exposid{inner_}@.@\exposid{emplace-deref}@(x); -}; +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); -for (; @\exposid{outer_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@); ++@\exposid{outer_}@) { - auto&& inner = update_inner(@\exposid{outer_}@); - @\exposid{inner_}@ = ranges::begin(inner); - if (@\exposid{inner_}@ != ranges::end(inner)) - return; + 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_}@); } + }; + + template + as_const_view(R&&) -> as_const_view>; } -if constexpr (@\exposid{ref-is-glvalue}@) - @\exposid{inner_}@ = @\exposid{InnerIter}@(); \end{codeblock} -\end{itemdescr} -\indexlibraryctor{join_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{OuterIter}@ outer); +constexpr explicit as_const_view(V base); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{outer_} with \tcode{std::move(outer)} and -\exposid{parent_} with \tcode{addressof(parent)}; then calls \tcode{\exposid{satisfy}()}. +Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\indexlibraryctor{join_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && - @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && - @\libconcept{convertible_to}@, @\exposid{InnerIter}@>; -\end{itemdecl} +\rSec2[range.elements]{Elements view} -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{outer_} with \tcode{std::move(i.\exposid{outer_})}, -\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}, and -\exposid{parent_} with \tcode{i.\exposid{parent_}}. -\end{itemdescr} +\rSec3[range.elements.overview]{Overview} -\indexlibrarymember{operator->}{join_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{InnerIter}@ operator->() const - requires @\exposconcept{has-arrow}@<@\exposid{InnerIter}@> && @\libconcept{copyable}@<@\exposid{InnerIter}@>; -\end{itemdecl} +\pnum +\tcode{elements_view} takes +a \libconcept{view} of tuple-like values and a \tcode{size_t}, and +produces a \libconcept{view} with a value-type of the $N^\text{th}$ element +of the adapted \libconcept{view}'s value-type. -\begin{itemdescr} \pnum -\effects -Equivalent to \tcode{return \exposid{inner_};} -\end{itemdescr} +\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\}}. -\indexlibrarymember{operator++}{join_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); -\end{itemdecl} +\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} -\begin{itemdescr} \pnum -Let \tcode{\placeholder{inner-range}} be: -\begin{itemize} -\item If \exposid{ref-is-glvalue} is \tcode{true}, \tcode{*\exposid{outer_}}. -\item Otherwise, \tcode{*\exposid{parent_}->\exposid{inner_}}. -\end{itemize} +\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 -\effects -Equivalent to: +\tcode{values_view} is an alias for \tcode{elements_view}, and +is useful for extracting values from associative containers. + +\begin{example} \begin{codeblock} -auto&& inner_rng = @\placeholder{inner-range}@; -if (++@\exposid{inner_}@ == ranges::end(inner_rng)) { - ++@\exposid{outer_}@; - @\exposid{satisfy}@(); +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_}@); } + + 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 + }; } -return *this; \end{codeblock} -\end{itemdescr} -\indexlibrarymember{operator++}{join_view::iterator}% +\indexlibraryctor{elements_view}% \begin{itemdecl} -constexpr void operator++(int); +constexpr explicit elements_view(V base); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{++*this}. +Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\indexlibrarymember{operator++}{join_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_range}@<@\exposid{Base}@> && - @\libconcept{forward_range}@>; -\end{itemdecl} +\rSec3[range.elements.iterator]{Class template \tcode{elements_view::\exposid{iterator}}} -\begin{itemdescr} -\pnum -\effects -Equivalent to: +\indexlibraryglobal{elements_view::iterator}% \begin{codeblock} -auto tmp = *this; -++*this; -return tmp; +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} -\end{itemdescr} -\indexlibrarymember{operator--}{join_view::iterator}% -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\libconcept{bidirectional_range}@> && - @\libconcept{common_range}@>; -\end{itemdecl} +\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} -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -if (@\exposid{outer_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) - @\exposid{inner_}@ = ranges::end(*--@\exposid{outer_}@); -while (@\exposid{inner_}@ == ranges::begin(*@\exposid{outer_}@)) - @\exposid{inner_}@ = ranges::end(*--@\exposid{outer_}@); ---@\exposid{inner_}@; -return *this; -\end{codeblock} -\end{itemdescr} +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} -\indexlibrarymember{operator--}{join_view::iterator}% +\indexlibrarymember{\exposid{get-element}}{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\libconcept{bidirectional_range}@> && - @\libconcept{common_range}@>; +static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); \end{itemdecl} \begin{itemdescr} @@ -6013,944 +8956,743 @@ \effects Equivalent to: \begin{codeblock} -auto tmp = *this; ---*this; -return tmp; +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} -\indexlibrarymember{operator==}{join_view::iterator}% +\indexlibraryctor{elements_view::iterator}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@> && - @\libconcept{equality_comparable}@>>; +constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return x.\exposid{outer_} == y.\exposid{outer_} \&\& x.\exposid{inner_} == y.\exposid{inner_};} +Initializes \exposid{current_} with \tcode{std::move(current)}. \end{itemdescr} -\indexlibrarymember{iter_swap}{join_view::iterator}% +\indexlibraryctor{elements_view::iterator}% \begin{itemdecl} -friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - noexcept(noexcept(ranges::iter_swap(x.@\exposid{inner_}@, y.@\exposid{inner_}@))) - requires @\libconcept{indirectly_swappable}@<@\exposid{InnerIter}@>; +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 ranges::iter_swap(x.\exposid{inner_}, y.\exposid{inner_});} +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. \end{itemdescr} -\rSec3[range.join.sentinel]{Class template \tcode{join_view::\exposid{sentinel}}} - -\indexlibraryglobal{join_view::sentinel}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V> - requires @\libconcept{view}@ && @\libconcept{input_range}@> - template - struct join_view::@\exposid{sentinel}@ { - private: - using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos - 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}@(@\exposid{Parent}@& parent); - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; - - template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); - }; -} -\end{codeblock} - -\indexlibraryctor{join_view::sentinel}% +\indexlibrarymember{base}{elements_view::iterator}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); +constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. +Equivalent to: \tcode{return \exposid{current_};} \end{itemdescr} -\indexlibraryctor{join_view::sentinel}% +\indexlibrarymember{base}{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +constexpr iterator_t<@\exposid{Base}@> base() &&; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{std::move(s.\exposid{end_})}. +Equivalent to: \tcode{return std::move(\exposid{current_});} \end{itemdescr} -\indexlibrarymember{operator==}{join_view::sentinel}%3431 - +\indexlibrarymember{operator++}{elements_view::iterator}% \begin{itemdecl} -template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{outer_} == y.\exposid{end_};} -\end{itemdescr} - -\rSec2[range.join.with]{Join with view} - -\rSec3[range.join.with.overview]{Overview} - -\pnum -\tcode{join_with_view} takes a \libconcept{view} and a delimiter, and -flattens the \libconcept{view}, -inserting every element of the delimiter -in between elements of the \libconcept{view}. -The delimiter can be a single element or a \libconcept{view} of elements. - -\pnum -\indexlibrarymember{join_with}{views}% -The name \tcode{views::join_with} denotes -a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{F}, -the expression \tcode{views::join_with(E, F)} is expression-equivalent to -\tcode{join_with_view(E, F)}. - -\pnum -\begin{example} -\begin{codeblock} -vector vs = {"the", "quick", "brown", "fox"}; -for (char c : vs | join_with('-')) { - cout << c; -} -\end{codeblock} -The above prints: \tcode{the-quick-brown-fox} -\end{example} - -\rSec3[range.join.with.view]{Class template \tcode{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> - class join_with_view : public view_interface> { - using @\exposid{InnerRng}@ = range_reference_t; // \expos - - V @\exposid{base_}@ = V(); // \expos - @\exposid{non-propagating-cache}@> @\exposid{inner_}@; // \expos, present only - // when \tcode{!is_reference_v<\exposid{InnerRng}>} - Pattern @\exposid{pattern_}@ = Pattern(); // \expos - - // \ref{range.join.with.iterator}, class template \tcode{join_with_view::\exposid{iterator}} - template struct @\exposid{iterator}@; // \expos - - // \ref{range.join.with.sentinel}, class template \tcode{join_with_view::\exposid{sentinel}} - template struct @\exposid{sentinel}@; // \expos - - public: - join_with_view() - requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - - constexpr join_with_view(V base, Pattern pattern); - - template - requires @\libconcept{constructible_from}@> && - @\libconcept{constructible_from}@>> - constexpr join_with_view(R&& r, range_value_t<@\exposid{InnerRng}@> e); - - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } - - constexpr auto begin() { - constexpr bool use_const = - @\exposconcept{simple-view}@ && is_reference_v<@\exposid{InnerRng}@> && @\exposconcept{simple-view}@; - return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; - } - constexpr auto begin() const - requires @\libconcept{input_range}@ && - @\libconcept{forward_range}@ && - is_reference_v> { - return @\exposid{iterator}@{*this, ranges::begin(@\exposid{base_}@)}; - } - - constexpr auto end() { - if constexpr (@\libconcept{forward_range}@ && - is_reference_v<@\exposid{InnerRng}@> && @\libconcept{forward_range}@<@\exposid{InnerRng}@> && - @\libconcept{common_range}@ && @\libconcept{common_range}@<@\exposid{InnerRng}@>) - return @\exposid{iterator}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@>{*this, ranges::end(@\exposid{base_}@)}; - else - return @\exposid{sentinel}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@>{*this}; - } - constexpr auto end() const - requires @\libconcept{input_range}@ && @\libconcept{forward_range}@ && - is_reference_v> { - using InnerConstRng = range_reference_t; - if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && - @\libconcept{common_range}@ && common_range) - return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; - else - return @\exposid{sentinel}@{*this}; - } - }; - - template - join_with_view(R&&, P&&) -> join_with_view, views::all_t

>; - - template<@\libconcept{input_range}@ R> - join_with_view(R&&, range_value_t>) - -> join_with_view, single_view>>>; -} +Equivalent to: +\begin{codeblock} +++@\exposid{current_}@; +return *this; \end{codeblock} +\end{itemdescr} +\indexlibrarymember{operator++}{elements_view::iterator}% \begin{itemdecl} -constexpr join_with_view(V base, Pattern pattern); +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{pattern_} with \tcode{std::move(pattern)}. +Equivalent to: \tcode{++\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator++}{elements_view::iterator}% \begin{itemdecl} -template<@\libconcept{input_range}@ R> - requires @\libconcept{constructible_from}@> && - @\libconcept{constructible_from}@>> -constexpr join_with_view(R&& r, range_value_t<@\exposid{InnerRng}@> e); +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{views::all(std::forward(r))} and -\exposid{pattern_} with \tcode{views::sin\-gle(std::move(e))}. +Equivalent to: +\begin{codeblock} +auto temp = *this; +++@\exposid{current_}@; +return temp; +\end{codeblock} \end{itemdescr} -\rSec3[range.join.with.iterator]{Class template \tcode{join_with_view::\exposid{iterator}}} +\indexlibrarymember{operator--}{elements_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \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> - template - class join_with_view::@\exposid{iterator}@ { - using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos - using @\exposid{InnerBase}@ = range_reference_t; // \expos - using @\exposid{PatternBase}@ = @\exposid{maybe-const}@; // \expos - - using @\exposid{OuterIter}@ = iterator_t<@\exposid{Base}@>; // \expos - using @\exposid{InnerIter}@ = iterator_t<@\exposid{InnerBase}@>; // \expos - using @\exposid{PatternIter}@ = iterator_t<@\exposid{PatternBase}@>; // \expos - - static constexpr bool @\exposid{ref-is-glvalue}@ = is_reference_v<@\exposid{InnerBase}@>; // \expos - - @\exposid{Parent}@* @\exposid{parent_}@ = nullptr; // \expos - @\exposid{OuterIter}@ @\exposid{outer_it_}@ = @\exposid{OuterIter}@(); // \expos - variant<@\exposid{PatternIter}@, @\exposid{InnerIter}@> @\exposid{inner_it_}@; // \expos - - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> outer); // \expos - constexpr auto&& @\exposid{update-inner}@(const @\exposid{OuterIter}@&); // \expos - constexpr auto&& @\exposid{get-inner}@(const @\exposid{OuterIter}@&); // \expos - constexpr void @\exposid{satisfy}@(); // \expos - - public: - using iterator_concept = @\seebelow@; - using iterator_category = @\seebelow@; // not always present - using value_type = @\seebelow@; - using difference_type = @\seebelow@; - - @\exposid{iterator}@() requires @\libconcept{default_initializable}@<@\exposid{OuterIter}@> = default; - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, @\exposid{OuterIter}@> && - @\libconcept{convertible_to}@, @\exposid{InnerIter}@> && - @\libconcept{convertible_to}@, @\exposid{PatternIter}@>; +--@\exposid{current_}@; +return *this; +\end{codeblock} +\end{itemdescr} - constexpr decltype(auto) operator*() const; +\indexlibrarymember{operator--}{elements_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +\end{itemdecl} - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_iterator}@<@\exposid{OuterIter}@> && - @\libconcept{forward_iterator}@<@\exposid{InnerIter}@>; +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto temp = *this; +--@\exposid{current_}@; +return temp; +\end{codeblock} +\end{itemdescr} - constexpr @\exposid{iterator}@& operator--() - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; - constexpr @\exposid{iterator}@ operator--(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; +\indexlibrarymember{operator+=}{elements_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator+=(difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@<@\exposid{OuterIter}@> && - @\libconcept{equality_comparable}@<@\exposid{InnerIter}@>; +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ += n; +return *this; +\end{codeblock} +\end{itemdescr} - friend constexpr decltype(auto) iter_move(const @\exposid{iterator}@& x) { - using rvalue_reference = common_reference_t< - iter_rvalue_reference_t<@\exposid{InnerIter}@>, - iter_rvalue_reference_t<@\exposid{PatternIter}@>>; - return visit(ranges::iter_move, x.@\exposid{inner_it_}@); - } +\indexlibrarymember{operator-=}{elements_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator-=(difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} - friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{indirectly_swappable}@<@\exposid{InnerIter}@, @\exposid{PatternIter}@> { - visit(ranges::iter_swap, x.@\exposid{inner_it_}@, y.@\exposid{inner_it_}@); - } - }; -} +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{current_}@ -= n; +return *this; \end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator==}{elements_view::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 -\tcode{\exposid{iterator}::iterator_concept} is defined as follows: -\begin{itemize} -\item -If \exposid{ref-is-glvalue} is \tcode{true}, -\exposid{Base} models \libconcept{bidirectional_range}, and -\exposid{InnerBase} and \exposid{PatternBase} -each model \exposconcept{bidirectional-common}, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item -Otherwise, if \exposid{ref-is-glvalue} is \tcode{true} and -\exposid{Base} and \exposid{InnerBase} each model \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 +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} +\end{itemdescr} + +\indexlibrarymember{operator<}{elements_view::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 -The member \grammarterm{typedef-name} \tcode{iterator_category} is defined -if and only if \exposid{ref-is-glvalue} is \tcode{true}, and -\exposid{Base} and \exposid{InnerBase} each model \libconcept{forward_range}. -In that case, -\tcode{\exposid{iterator}::iterator_category} is defined as follows: +\effects +Equivalent to: \tcode{return x.\exposid{current_} < y.\exposid{current_};} +\end{itemdescr} -\begin{itemize} -\item -Let \placeholder{OUTERC} denote -\tcode{iterator_traits<\exposid{OuterIter}>::iterator_category}, -let \placeholder{INNERC} denote -\tcode{iterator_traits<\exposid{InnerIter}>::iterator_category}, and -let \placeholder{PATTERNC} denote -\tcode{iterator_-\linebreak traits<\exposid{PatternIter}>::iterator_category}. -\item -If -\begin{codeblock} -is_lvalue_reference_v, - iter_reference_t<@\exposid{PatternIter}@>>> -\end{codeblock} -is \tcode{false}, -\tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\item -Otherwise, -if \placeholder{OUTERC}, \placeholder{INNERC}, and \placeholder{PATTERNC} -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}. -\item -Otherwise, -if \placeholder{OUTERC}, \placeholder{INNERC}, and \placeholder{PATTERNC} -each model \tcode{\libconcept{derived_from}}, -\tcode{iterator_category} denotes \tcode{forward_iterator_tag}. -\item -Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\end{itemize} +\indexlibrarymember{operator>}{elements_view::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 -\tcode{\exposid{iterator}::value_type} denotes the type: -\begin{codeblock} -common_type_t, iter_value_t<@\exposid{PatternIter}@>> -\end{codeblock} +\effects +Equivalent to: \tcode{return y < x;} +\end{itemdescr} + +\indexlibrarymember{operator<=}{elements_view::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 -\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}@>> -\end{codeblock} +\effects +Equivalent to: \tcode{return !(y < x);} +\end{itemdescr} +\indexlibrarymember{operator>=}{elements_view::iterator}% \begin{itemdecl} -constexpr auto&& @\exposid{update-inner}@(const @\exposid{OuterIter}@& x); +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} -if constexpr (@\exposid{ref-is-glvalue}@) - return *x; -else - return @\exposid{parent_}@->@\exposid{inner_}@.@\exposid{emplace-deref}@(x); -\end{codeblock} +Equivalent to: \tcode{return !(x < y);} \end{itemdescr} +\indexlibrarymember{operator<=>}{elements_view::iterator}% \begin{itemdecl} -constexpr auto&& @\exposid{get-inner}@(const @\exposid{OuterIter}@& x); +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: -\begin{codeblock} -if constexpr (@\exposid{ref-is-glvalue}@) - return *x; -else - return *@\exposid{parent_}@->@\exposid{inner_}@; -\end{codeblock} +Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};} \end{itemdescr} +\indexlibrarymember{operator+}{elements_view::iterator}% \begin{itemdecl} -constexpr void @\exposid{satisfy}@(); +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} -while (true) { - if (@\exposid{inner_it_}@.index() == 0) { - if (std::get<0>(@\exposid{inner_it_}@) != ranges::end(@\exposid{parent_}@->@\exposid{pattern_}@)) - break; - auto&& inner = @\exposid{update-inner}@(@\exposid{outer_it_}@); - @\exposid{inner_it_}@.emplace<1>(ranges::begin(inner)); - } else { - auto&& inner = @\exposid{get-inner}@(@\exposid{outer_it_}@); - if (std::get<1>(@\exposid{inner_it_}@) != ranges::end(inner)) - break; - if (++@\exposid{outer_it_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { - if constexpr (@\exposid{ref-is-glvalue}@) - @\exposid{inner_it_}@.emplace<0>(); - break; - } - @\exposid{inner_it_}@.emplace<0>(ranges::begin(@\exposid{parent_}@->@\exposid{pattern_}@)); - } -} -\end{codeblock} - -\begin{note} -\tcode{join_with_view} iterators use the \exposid{satisfy} function -to skip over empty inner ranges. -\end{note} +Equivalent to: \tcode{return \exposid{iterator}\{x\} += y;} \end{itemdescr} +\indexlibrarymember{operator+}{elements_view::iterator}% \begin{itemdecl} -constexpr iterator(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> outer); +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 -Initializes \exposid{parent_} with \tcode{addressof(parent)} and -\exposid{outer_it_} with \tcode{std::move(outer)}. -Then, equivalent to: -\begin{codeblock} -if (@\exposid{outer_it_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { - auto&& inner = @\exposid{update-inner}@(@\exposid{outer_it_}@); - @\exposid{inner_it_}@.emplace<1>(ranges::begin(inner)); - @\exposidnc{satisfy}@(); -} -\end{codeblock} +Equivalent to: \tcode{return y + x;} \end{itemdescr} +\indexlibrarymember{operator-}{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && convertible_to, @\exposid{OuterIter}@> && - convertible_to, @\exposid{InnerIter}@> && - convertible_to, @\exposid{PatternIter}@>; +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 -Initializes \exposid{outer_it_} with -\tcode{std::move(i.\exposid{outer_it_})} and -\exposid{parent_} with \tcode{i.\exposid{parent_}}. -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_}@))); -else - @\exposid{inner_it_}@.emplace<1>(std::get<1>(std::move(i.@\exposid{inner_it_}@))); -\end{codeblock} +Equivalent to: \tcode{return \exposid{iterator}\{x\} -= y;} \end{itemdescr} +\indexlibrarymember{operator-}{elements_view::iterator}% \begin{itemdecl} -constexpr decltype(auto) operator*() const; +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: +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::sentinel}% \begin{codeblock} -using reference = - common_reference_t, iter_reference_t<@\exposid{PatternIter}@>>; -return visit([](auto& it) -> reference { return *it; }, @\exposid{inner_it_}@); +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} -\end{itemdescr} +\indexlibraryctor{elements_view::sentinel}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -visit([](auto& it){ ++it; }, @\exposid{inner_it_}@); -@\exposidnc{satisfy}@(); -return *this; -\end{codeblock} +Initializes \exposid{end_} with \tcode{end}. \end{itemdescr} +\indexlibraryctor{elements_view::sentinel}% \begin{itemdecl} -constexpr void operator++(int); +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{++*this}. +Initializes \exposid{end_} with \tcode{std::move(other.\exposid{end_})}. \end{itemdescr} +\indexlibrarymember{base}{elements_view::sentinel}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{forward_iterator}@<@\exposid{OuterIter}@> && @\libconcept{forward_iterator}@<@\exposid{InnerIter}@>; +constexpr sentinel_t<@\exposid{Base}@> base() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -@\exposid{iterator}@ tmp = *this; -++*this; -return tmp; -\end{codeblock} +Equivalent to: \tcode{return \exposid{end_};} \end{itemdescr} +\indexlibrarymember{operator==}{elements_view::sentinel}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; +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: -\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)); -} - -while (true) { - if (@\exposid{inner_it_}@.index() == 0) { - 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)); - } else { - break; - } - } else { - 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_}@)); - } else { - break; - } - } -} -visit([](auto& it){ --it; }, @\exposid{inner_it_}@); -return *this; -\end{codeblock} +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} \end{itemdescr} +\indexlibrarymember{operator-}{elements_view::sentinel}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{bidirectional_range}@<@\exposid{Base}@> && - @\exposconcept{bidirectional-common}@<@\exposid{InnerBase}@> && @\exposconcept{bidirectional-common}@<@\exposid{PatternBase}@>; +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: -\begin{codeblock} -@\exposid{iterator}@ tmp = *this; ---*this; -return tmp; -\end{codeblock} +Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{end_};} \end{itemdescr} +\indexlibrarymember{operator-}{elements_view::sentinel}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposid{ref-is-glvalue}@ && @\libconcept{equality_comparable}@<@\exposid{OuterIter}@> && - @\libconcept{equality_comparable}@<@\exposid{InnerIter}@>; +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: +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 \libconcept{view}s and +produces a \libconcept{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} -return x.@\exposid{outer_it_}@ == y.@\exposid{outer_it_}@ && x.@\exposid{inner_it_}@ == y.@\exposid{inner_it_}@; +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{itemdescr} +\end{example} + +\rSec3[range.zip.view]{Class template \tcode{zip_view}} + +\indexlibrarymember{begin}{zip_view}% +\indexlibrarymember{end}{zip_view}% +\indexlibrarymember{size}{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}@ && ...)); -\rSec3[range.join.with.sentinel]{Class template \tcode{join_with_view::\exposid{sentinel}}} + template<@\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) + class zip_view : public view_interface> { + tuple @\exposid{views_}@; // \expos -\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> - template - class join_with_view::@\exposid{sentinel}@ { - using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos - sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + // \ref{range.zip.iterator}, class template \tcode{zip_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos - constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); // \expos + // \ref{range.zip.sentinel}, class template \tcode{zip_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos public: - @\exposid{sentinel}@() = default; - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + zip_view() = default; + constexpr explicit zip_view(Views... views); - template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); -}; -\end{codeblock} + 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_}@)); + } -\begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); -\end{itemdecl} + 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} -\begin{itemdescr} \pnum -\effects -Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. -\end{itemdescr} +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 @\exposid{sentinel}@(@\exposid{sentinel}@ s) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; +constexpr explicit zip_view(Views... views); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{std::move(s.\exposid{end_})}. +Initializes \exposid{views_} with \tcode{std::move(views)...}. \end{itemdescr} \begin{itemdecl} -template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> -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{outer_it_} == y.\exposid{end_};} -\end{itemdescr} - -\rSec2[range.lazy.split]{Lazy split view} - -\rSec3[range.lazy.split.overview]{Overview} - -\pnum -\tcode{lazy_split_view} takes a \libconcept{view} and a delimiter, and splits -the \libconcept{view} into subranges on the delimiter. The delimiter can be -a single element or a \libconcept{view} of elements. - -\pnum -\indexlibrarymember{lazy_split}{views}% -The name \tcode{views::lazy_split} denotes a -range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{F}, -the expression \tcode{views::lazy_split(E, F)} is expression-equivalent to -\tcode{lazy_split_view(E, F)}. - -\pnum -\begin{example} +Equivalent to: \begin{codeblock} -string str{"the quick brown fox"}; -for (auto word : str | views::lazy_split(' ')) { - for (char ch : word) - cout << ch; - cout << '*'; -} -// The above prints: the*quick*brown*fox* +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{example} +\end{itemdescr} -\rSec3[range.lazy.split.view]{Class template \tcode{lazy_split_view}} +\rSec3[range.zip.iterator]{Class template \tcode{zip_view::\exposid{iterator}}} -\indexlibraryglobal{lazy_split_view}% -\indexlibrarymember{base}{lazy_split_view}% -\indexlibrarymember{begin}{lazy_split_view}% -\indexlibrarymember{end}{lazy_split_view}% +\indexlibraryglobal{zip_view::iterator}% \begin{codeblock} namespace std::ranges { - template struct @\exposidnc{require-constant}@; // \expos - - template - concept @\defexposconceptnc{tiny-range}@ = // \expos - @\libconcept{sized_range}@ && - requires { typename @\exposid{require-constant}@::size()>; } && - (remove_reference_t::size() <= 1); + 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}@ V, @\libconcept{forward_range}@ Pattern> - requires @\libconcept{view}@ && @\libconcept{view}@ && - @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && - (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) - class lazy_split_view : public view_interface> { - private: - V @\exposid{base_}@ = V(); // \expos - Pattern @\exposid{pattern_}@ = Pattern(); // \expos + 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>...>; - @\exposidnc{non-propagating-cache}@> @\exposid{current_}@; // \expos, present only - // if \tcode{!\libconcept{forward_range}} + @\exposid{iterator}@() = default; + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && (@\libconcept{convertible_to}@, iterator_t> && ...); - // \ref{range.lazy.split.outer}, class template \tcode{lazy_split_view::\exposid{outer-iterator}} - template struct @\exposidnc{outer-iterator}@; // \expos + constexpr auto operator*() const; + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\exposconcept{all-forward}@; - // \ref{range.lazy.split.inner}, class template \tcode{lazy_split_view::\exposid{inner-iterator}} - template struct @\exposidnc{inner-iterator}@; // \expos + constexpr @\exposid{iterator}@& operator--() requires @\exposconcept{all-bidirectional}@; + constexpr @\exposid{iterator}@ operator--(int) requires @\exposconcept{all-bidirectional}@; - public: - lazy_split_view() - requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr lazy_split_view(V base, Pattern pattern); + constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\exposconcept{all-random-access}@; + constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\exposconcept{all-random-access}@; - template<@\libconcept{input_range}@ R> - requires @\libconcept{constructible_from}@> && - @\libconcept{constructible_from}@>> - constexpr lazy_split_view(R&& r, range_value_t e); + constexpr auto operator[](difference_type n) const + requires @\exposconcept{all-random-access}@; - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{equality_comparable}@>> && ...); - constexpr auto begin() { - if constexpr (@\libconcept{forward_range}@) { - return @\exposid{outer-iterator}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@> - {*this, ranges::begin(@\exposid{base_}@)}; - } else { - @\exposid{current_}@ = ranges::begin(@\exposid{base_}@); - return @\exposid{outer-iterator}@{*this}; - } - } + friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; - constexpr auto begin() const requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ { - return @\exposid{outer-iterator}@{*this, ranges::begin(@\exposid{base_}@)}; - } + 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}@>> && ...); - constexpr auto end() requires @\libconcept{forward_range}@ && @\libconcept{common_range}@ { - return @\exposid{outer-iterator}@<@\exposconcept{simple-view}@ && @\exposconcept{simple-view}@> - {*this, ranges::end(@\exposid{base_}@)}; - } + friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); - constexpr auto end() const { - if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && @\libconcept{common_range}@) - return @\exposid{outer-iterator}@{*this, ranges::end(@\exposid{base_}@)}; - else - return default_sentinel; - } + friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires (@\libconcept{indirectly_swappable}@>> && ...); }; - - template - lazy_split_view(R&&, P&&) -> lazy_split_view, views::all_t

>; - - template<@\libconcept{input_range}@ R> - lazy_split_view(R&&, range_value_t) - -> lazy_split_view, single_view>>; } \end{codeblock} -\indexlibraryctor{lazy_split_view}% +\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. + \begin{itemdecl} -constexpr lazy_split_view(V base, Pattern pattern); +constexpr explicit @\exposid{iterator}@(tuple>...> current); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)}, and -\exposid{pattern_} with \tcode{std::move(pattern)}. +Initializes \exposid{current_} with \tcode{std::move(current)}. \end{itemdescr} -\indexlibraryctor{lazy_split_view}% \begin{itemdecl} -template<@\libconcept{input_range}@ R> - requires @\libconcept{constructible_from}@> && - @\libconcept{constructible_from}@>> -constexpr lazy_split_view(R&& r, range_value_t e); +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && (@\libconcept{convertible_to}@, iterator_t> && ...); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{views::all(std::forward(r))}, and -\exposid{pattern_} with \tcode{views::\linebreak single(std::move(e))}. +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. \end{itemdescr} -\rSec3[range.lazy.split.outer]{Class template \tcode{lazy_split_view::\exposid{outer-iterator}}} +\begin{itemdecl} +constexpr auto operator*() const; +\end{itemdecl} -\indexlibraryglobal{lazy_split_view::\exposid{outer-iterator}}% +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> - requires @\libconcept{view}@ && @\libconcept{view}@ && - @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && - (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) - template - struct lazy_split_view::@\exposid{outer-iterator}@ { - private: - using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos - - iterator_t<@\exposidnc{Base}@> @\exposid{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos, present only - // if \tcode{V} models \libconcept{forward_range} - - bool @\exposid{trailing_empty_}@ = false; // \expos - - public: - using iterator_concept = - conditional_t<@\libconcept{forward_range}@<@\exposid{Base}@>, forward_iterator_tag, input_iterator_tag>; - - using iterator_category = input_iterator_tag; // present only if \exposid{Base} - // models \libconcept{forward_range} - - // \ref{range.lazy.split.outer.value}, class \tcode{lazy_split_view::\exposid{outer-iterator}::value_type} - struct value_type; - using difference_type = range_difference_t<@\exposid{Base}@>; - - @\exposid{outer-iterator}@() = default; - constexpr explicit @\exposid{outer-iterator}@(@\exposid{Parent}@& parent) - requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); - constexpr @\exposid{outer-iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current) - requires @\libconcept{forward_range}@<@\exposid{Base}@>; - constexpr @\exposid{outer-iterator}@(@\exposid{outer-iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; - - constexpr value_type operator*() const; - - constexpr @\exposid{outer-iterator}@& operator++(); - constexpr decltype(auto) operator++(int) { - if constexpr (@\libconcept{forward_range}@<@\exposid{Base}@>) { - auto tmp = *this; - ++*this; - return tmp; - } else - ++*this; - } - - friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, const @\exposid{outer-iterator}@& y) - requires @\libconcept{forward_range}@<@\exposid{Base}@>; - - friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); - }; -} +return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); \end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator++(); +\end{itemdecl} +\begin{itemdescr} \pnum -Many of the specifications in \ref{range.lazy.split} refer to the notional member -\placeholder{current} of \exposid{outer-iterator}. -\placeholder{current} is equivalent to \exposid{current_} if \tcode{V} -models \libconcept{forward_range}, and \tcode{*\exposid{parent_}->\exposid{current_}} otherwise. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{tuple-for-each}@([](auto& i) { ++i; }, @\exposid{current_}@); +return *this; +\end{codeblock} +\end{itemdescr} -\indexlibraryctor{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr explicit @\exposid{outer-iterator}@(@\exposid{Parent}@& parent) - requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}. +Equivalent to \tcode{++*this}. \end{itemdescr} -\indexlibraryctor{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr @\exposid{outer-iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current) - requires @\libconcept{forward_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator++(int) requires @\exposconcept{all-forward}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)} -and \exposid{current_} with \tcode{std::move(current)}. +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} \end{itemdescr} -\indexlibraryctor{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr @\exposid{outer-iterator}@(@\exposid{outer-iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@& operator--() requires @\exposconcept{all-bidirectional}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and -\exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +Equivalent to: +\begin{codeblock} +@\exposid{tuple-for-each}@([](auto& i) { --i; }, @\exposid{current_}@); +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator*}{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr value_type operator*() const; +constexpr @\exposid{iterator}@ operator--(int) requires @\exposconcept{all-bidirectional}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return value_type\{*this\};} +Equivalent to: +\begin{codeblock} +auto tmp = *this; +--*this; +return tmp; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -constexpr @\exposid{outer-iterator}@& operator++(); +constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -6958,40 +9700,14 @@ \effects Equivalent to: \begin{codeblock} -const auto end = ranges::end(@\exposid{parent_}@->@\exposid{base_}@); -if (@\placeholder{current}@ == end) { - @\exposid{trailing_empty_}@ = false; - return *this; -} -const auto [pbegin, pend] = subrange{@\exposid{parent_}@->@\exposid{pattern_}@}; -if (pbegin == pend) ++@\placeholder{current}@; -else if constexpr (@\exposconcept{tiny-range}@) { - @\placeholder{current}@ = ranges::find(std::move(@\placeholder{current}@), end, *pbegin); - if (@\placeholder{current}@ != end) { - ++@\placeholder{current}@; - if (@\placeholder{current}@ == end) - @\exposid{trailing_empty_}@ = true; - } -} -else { - do { - auto [b, p] = ranges::mismatch(@\placeholder{current}@, end, pbegin, pend); - if (p == pend) { - @\placeholder{current}@ = b; - if (@\placeholder{current}@ == end) - @\exposid{trailing_empty_}@ = true; - break; // The pattern matched; skip it - } - } while (++@\placeholder{current}@ != end); -} +@\exposid{tuple-for-each}@([&](I& i) { i += iter_difference_t(x); }, @\exposid{current_}@); return *this; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator==}{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, const @\exposid{outer-iterator}@& y) - requires @\libconcept{forward_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -6999,13 +9715,14 @@ \effects Equivalent to: \begin{codeblock} -return x.@\exposid{current_}@ == y.@\exposid{current_}@ && x.@\exposid{trailing_empty_}@ == y.@\exposid{trailing_empty_}@; +@\exposid{tuple-for-each}@([&](I& i) { i -= iter_difference_t(x); }, @\exposid{current_}@); +return *this; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator==}{lazy_split_view::\exposid{outer-iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); +constexpr auto operator[](difference_type n) const + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -7013,453 +9730,531 @@ \effects Equivalent to: \begin{codeblock} -return x.@\placeholdernc{current}@ == ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) && !x.@\exposid{trailing_empty_}@; +return @\exposid{tuple-transform}@([&](I& i) -> decltype(auto) { + return i[iter_difference_t(n)]; +}, @\exposid{current_}@); \end{codeblock} \end{itemdescr} -\rSec3[range.lazy.split.outer.value]{Class \tcode{lazy_split_view::\exposid{outer-iterator}::value_type}} +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires (@\libconcept{equality_comparable}@>> && ...); +\end{itemdecl} -\indexlibraryglobal{lazy_split_view::\exposid{outer-iterator}::value_type}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> - requires @\libconcept{view}@ && @\libconcept{view}@ && - @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && - (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) - template - struct lazy_split_view::@\exposid{outer-iterator}@::value_type - : view_interface { - private: - @\exposid{outer-iterator}@ @\exposid{i_}@ = @\exposid{outer-iterator}@(); // \expos - public: - value_type() = default; - constexpr explicit value_type(@\exposid{outer-iterator}@ i); +\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} - constexpr @\exposid{inner-iterator}@ begin() const; - constexpr default_sentinel_t end() const noexcept; - }; -} +\begin{itemdecl} +friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{all-random-access}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. +\end{itemdescr} + +\begin{itemdecl} +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: +\begin{codeblock} +auto r = i; +r += n; +return r; \end{codeblock} +\end{itemdescr} -\indexlibraryctor{lazy_split_view::\exposid{outer-iterator}::value_type}% \begin{itemdecl} -constexpr explicit value_type(@\exposid{outer-iterator}@ i); +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\exposconcept{all-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{i_} with \tcode{std::move(i)}. +Equivalent to: +\begin{codeblock} +auto r = i; +r -= n; +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{begin}{lazy_split_view::\exposid{outer-iterator}::value_type}% \begin{itemdecl} -constexpr @\exposid{inner-iterator}@ begin() const; +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@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{inner-iterator}\{\exposid{i_}\};} +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} -\indexlibrarymember{end}{lazy_split_view::\exposid{outer-iterator}::value_type}% \begin{itemdecl} -constexpr default_sentinel_t end() const 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 default_sentinel;} +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.lazy.split.inner]{Class template \tcode{lazy_split_view::\exposid{inner-iterator}}} +\rSec3[range.zip.sentinel]{Class template \tcode{zip_view::\exposid{sentinel}}} -\indexlibraryglobal{lazy_split_view::\exposid{inner-iterator}}% +\indexlibraryglobal{zip_view::sentinel}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ V, @\libconcept{forward_range}@ Pattern> - requires @\libconcept{view}@ && @\libconcept{view}@ && - @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> && - (@\libconcept{forward_range}@ || @\exposconcept{tiny-range}@) + template<@\libconcept{input_range}@... Views> + requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) template - struct lazy_split_view::@\exposid{inner-iterator}@ { - private: - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - @\exposidnc{outer-iterator}@ @\exposid{i_}@ = @\exposidnc{outer-iterator}@(); // \expos - bool @\exposid{incremented_}@ = false; // \expos - + class zip_view::@\exposid{sentinel}@ { + tuple>...> @\exposid{end_}@;@\itcorr[-1]@ // \expos + constexpr explicit @\exposidnc{sentinel}@(tuple>...> end); + // \expos public: - using iterator_concept = typename @\exposid{outer-iterator}@::iterator_concept; - - using iterator_category = @\seebelownc@; // present only if \exposid{Base} - // models \libconcept{forward_range} - using value_type = range_value_t<@\exposid{Base}@>; - using difference_type = range_difference_t<@\exposid{Base}@>; - - @\exposid{inner-iterator}@() = default; - constexpr explicit @\exposid{inner-iterator}@(@\exposid{outer-iterator}@ i); - - constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; - constexpr iterator_t<@\exposid{Base}@> base() && requires @\libconcept{forward_range}@; - - constexpr decltype(auto) operator*() const { return *@\exposid{i_}@.@\placeholder{current}@; } - - constexpr @\exposid{inner-iterator}@& operator++(); - constexpr decltype(auto) operator++(int) { - if constexpr (@\libconcept{forward_range}@<@\exposid{Base}@>) { - auto tmp = *this; - ++*this; - return tmp; - } else - ++*this; - } - - friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) - requires @\libconcept{forward_range}@<@\exposid{Base}@>; + @\exposid{sentinel}@() = default; + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) + requires Const && (@\libconcept{convertible_to}@, sentinel_t> && ...); - friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); + template + requires (@\libconcept{sentinel_for}@>, + iterator_t<@\exposid{maybe-const}@>> && ...) + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); - friend constexpr decltype(auto) iter_move(const @\exposid{inner-iterator}@& i) - noexcept(noexcept(ranges::iter_move(i.@\exposid{i_}@.@\placeholdernc{current}@))) { - return ranges::iter_move(i.@\exposid{i_}@.@\placeholdernc{current}@); - } + 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); - friend constexpr void iter_swap(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) - noexcept(noexcept(ranges::iter_swap(x.@\exposid{i_}@.@\placeholdernc{current}@, y.@\exposid{i_}@.@\placeholdernc{current}@))) - requires @\libconcept{indirectly_swappable}@>; + 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); }; } \end{codeblock} -\pnum -If \exposid{Base} does not model \libconcept{forward_range} -there is no member \tcode{iterator_category}. -Otherwise, the \grammarterm{typedef-name} \tcode{iterator_category} denotes: -\begin{itemize} -\item -\tcode{forward_iterator_tag} if -\tcode{iterator_traits>::iterator_category} models \linebreak -\tcode{\libconcept{derived_from}}; -\item otherwise, \tcode{iterator_traits>::iterator_category}. -\end{itemize} - -\indexlibraryctor{lazy_split_view::\exposid{inner-iterator}}% -\begin{itemdecl} -constexpr explicit @\exposid{inner-iterator}@(@\exposid{outer-iterator}@ i); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{i_} with \tcode{std::move(i)}. -\end{itemdescr} - -\indexlibrarymember{base}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +constexpr explicit @\exposid{sentinel}@(tuple>...> end); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{i_}.\placeholder{current};} +Initializes \exposid{end_} with \tcode{end}. \end{itemdescr} -\indexlibrarymember{base}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() && requires @\libconcept{forward_range}@; +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) + requires Const && (@\libconcept{convertible_to}@, sentinel_t> && ...); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return std::move(\exposid{i_}.\placeholder{current});} +Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. \end{itemdescr} -\indexlibrarymember{operator++}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -constexpr @\exposid{inner-iterator}@& operator++(); +template + 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: -\begin{codeblock} -@\exposid{incremented_}@ = true; -if constexpr (!@\libconcept{forward_range}@<@\exposid{Base}@>) { - if constexpr (Pattern::size() == 0) { - return *this; - } -} -++@\exposid{i_}@.@\placeholder{current}@; -return *this; -\end{codeblock} +\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==}{lazy_split_view::\exposid{inner-iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, const @\exposid{inner-iterator}@& y) - requires @\libconcept{forward_range}@<@\exposid{Base}@>; +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); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{i_}.\placeholder{current} == y.\exposid{i_}.\placeholder{current};} -\end{itemdescr} - -\indexlibrarymember{operator==}{lazy_split_view::\exposid{inner-iterator}}% -\begin{itemdecl} -friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); -\end{itemdecl} +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_}))}. -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto [pcur, pend] = subrange{x.@\exposid{i_}@.@\exposid{parent_}@->@\exposid{pattern_}@}; -auto end = ranges::end(x.@\exposid{i_}@.@\exposid{parent_}@->@\exposid{base_}@); -if constexpr (@\exposconcept{tiny-range}@) { - const auto & cur = x.@\exposid{i_}@.@\placeholder{current}@; - if (cur == end) return true; - if (pcur == pend) return x.@\exposid{incremented_}@; - return *cur == *pcur; -} else { - auto cur = x.@\exposid{i_}@.@\placeholder{current}@; - if (cur == end) return true; - if (pcur == pend) return x.@\exposid{incremented_}@; - do { - if (*cur != *pcur) return false; - if (++pcur == pend) return true; - } while (++cur != end); - return false; -} -\end{codeblock} +\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{iter_swap}{lazy_split_view::\exposid{inner-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{i_}@.@\placeholdernc{current}@, y.@\exposid{i_}@.@\placeholdernc{current}@))) - requires @\libconcept{indirectly_swappable}@>; +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); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to -\tcode{ranges::iter_swap(x.\exposid{i_}.\placeholdernc{current}, y.\exposid{i_}.\placeholdernc{current})}. +Equivalent to \tcode{return -(x - y);} \end{itemdescr} -\rSec2[range.split]{Split view} - -\rSec3[range.split.overview]{Overview} +\rSec2[range.zip.transform]{Zip transform view} -\pnum -\tcode{split_view} takes a \libconcept{view} and a delimiter, and -splits the \libconcept{view} into \tcode{subrange}s on the delimiter. -The delimiter can be a single element or a \libconcept{view} of elements. +\rSec3[range.zip.transform.overview]{Overview} \pnum -The name \tcode{views::split} denotes -a range adaptor object\iref{range.adaptor.object}. -Given subexpressions \tcode{E} and \tcode{F}, -the expression \tcode{views::split(E, F)} is expression-equivalent to -\tcode{split_view(E, F)}. +\indexlibraryglobal{zip_transform_view}% +\tcode{zip_transform_view} takes an invocable object and +any number of \libconcept{view}s and +produces a \libconcept{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}. +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}. +\begin{itemize} +\item +If \tcode{\libconcept{copy_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} -string str{"the quick brown fox"}; -for (string_view word : split(str, ' ')) { - cout << word << '*'; +vector v1 = {1, 2}; +vector v2 = {4, 5, 6}; + +for (auto i : views::zip_transform(plus(), v1, v2)) { + cout << i << ' '; // prints \tcode{5 7} } -// The above prints: the*quick*brown*fox* \end{codeblock} \end{example} -\rSec3[range.split.view]{Class template \tcode{split_view}} +\rSec3[range.zip.transform.view]{Class template \tcode{zip_transform_view}} +\indexlibrarymember{begin}{zip_transform_view}% +\indexlibrarymember{end}{zip_transform_view}% +\indexlibrarymember{size}{zip_transform_view}% \begin{codeblock} namespace std::ranges { - 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 : public view_interface> { - private: - V @\exposid{base_}@ = V(); // \expos - Pattern @\exposid{pattern_}@ = Pattern(); // \expos + 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 - // \ref{range.split.iterator}, class \tcode{split_view::\exposid{iterator}} - struct @\exposid{iterator}@; // \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.split.sentinel}, class \tcode{split_view::\exposid{sentinel}} - struct @\exposid{sentinel}@; // \expos + // \ref{range.zip.transform.iterator}, class template \tcode{zip_transform_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos + + // \ref{range.zip.transform.sentinel}, class template \tcode{zip_transform_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos public: - split_view() - requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr split_view(V base, Pattern pattern); + zip_transform_view() = default; - template<@\libconcept{forward_range}@ R> - requires @\libconcept{constructible_from}@> && - @\libconcept{constructible_from}@>> - constexpr split_view(R&& r, range_value_t e); + 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 @\exposid{iterator}@ begin(); + constexpr auto begin() const + requires @\libconcept{range}@ && + @\libconcept{regular_invocable}@...> { + return @\exposid{iterator}@(*this, @\exposid{zip_}@.begin()); + } constexpr auto end() { - if constexpr (@\libconcept{common_range}@) { - return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@), {}}; + if constexpr (@\libconcept{common_range}@<@\exposid{InnerView}@>) { + return @\exposid{iterator}@(*this, @\exposid{zip_}@.end()); } else { - return @\exposid{sentinel}@{*this}; + return @\exposid{sentinel}@(@\exposid{zip_}@.end()); } } - constexpr subrange> @\exposid{find-next}@(iterator_t); // \expos - }; + 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{sentinel}@(@\exposid{zip_}@.end()); + } + } - template - split_view(R&&, P&&) -> split_view, views::all_t

>; + constexpr auto size() requires @\libconcept{sized_range}@<@\exposid{InnerView}@> { + return @\exposid{zip_}@.size(); + } - template<@\libconcept{forward_range}@ R> - split_view(R&&, range_value_t) - -> split_view, single_view>>; + constexpr auto size() const requires @\libconcept{sized_range}@ { + return @\exposid{zip_}@.size(); + } + }; + + template + zip_transform_view(F, Rs&&...) -> zip_transform_view...>; } \end{codeblock} \begin{itemdecl} -constexpr split_view(V base, Pattern pattern); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)}, and -\exposid{pattern_} with \tcode{std::move(pattern)}. -\end{itemdescr} - -\indexlibraryctor{split_view}% -\begin{itemdecl} -template<@\libconcept{forward_range}@ R> - requires @\libconcept{constructible_from}@> && - @\libconcept{constructible_from}@>> -constexpr split_view(R&& r, range_value_t e); +constexpr explicit zip_transform_view(F fun, Views... views); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{views::all(std::forward(r))}, and -\exposid{pattern_} with \tcode{views::\linebreak single(std::move(e))}. +Initializes \exposid{fun_} with \tcode{std::move(fun)} and +\exposid{zip_} with \tcode{std::move(views)...}. \end{itemdescr} -\begin{itemdecl} -constexpr @\exposid{iterator}@ begin(); -\end{itemdecl} +\rSec3[range.zip.transform.iterator]{Class template \tcode{zip_transform_view::\exposid{iterator}}} -\begin{itemdescr} -\pnum -\returns -\tcode{\{*this, ranges::begin(\exposid{base_}), \exposid{find-next}(ranges::begin(\exposid{base_}))\}}. +\indexlibraryglobal{zip_transform_view::iterator}% +\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 -\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{split_view} -for use on subsequent calls. -\end{itemdescr} + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); // \expos -\begin{itemdecl} -constexpr subrange> @\exposid{find-next}@(iterator_t it); // \expos -\end{itemdecl} + 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 difference_type = range_difference_t<@\exposid{Base}@>; -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -auto [b, e] = ranges::search(subrange(it, ranges::end(@\exposid{base_}@)), @\exposid{pattern_}@); -if (b != ranges::end(@\exposid{base_}@) && ranges::empty(@\exposid{pattern_}@)) { - ++b; - ++e; -} -return {b, e}; -\end{codeblock} -\end{itemdescr} + @\exposid{iterator}@() = default; + constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; -\rSec3[range.split.iterator]{Class \tcode{split_view::\exposid{iterator}}} + constexpr decltype(auto) operator*() const noexcept(@\seebelow@); + constexpr @\exposid{iterator}@& operator++(); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; -\begin{codeblock} -namespace std::ranges { - 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::@\exposid{iterator}@ { - private: - split_view* @\exposid{parent_}@ = nullptr; // \expos - iterator_t @\exposid{cur_}@ = iterator_t(); // \expos - subrange> @\exposid{next_}@ = subrange>(); // \expos - bool @\exposid{trailing_empty_}@ = false; // \expos + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - public: - using iterator_concept = forward_iterator_tag; - using iterator_category = input_iterator_tag; - using value_type = subrange>; - using difference_type = range_difference_t; + 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}@>; - @\exposid{iterator}@() = default; - constexpr @\exposid{iterator}@(split_view& parent, iterator_t current, subrange> next); + constexpr decltype(auto) operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr iterator_t base() const; - constexpr value_type operator*() const; + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{equality_comparable}@<@\exposid{ziperator}@>; - constexpr @\exposid{iterator}@& operator++(); - constexpr @\exposid{iterator}@ operator++(int); + friend constexpr auto 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); + 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{ziperator}@, @\exposid{ziperator}@>; }; } \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 an lvalue 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{(\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{itera\-tor_category} denotes \tcode{bidirectional_iterator_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} + \begin{itemdecl} -constexpr @\exposid{iterator}@(split_view& parent, iterator_t current, subrange> next); +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}, -\exposid{cur_} with \tcode{std::move(current)}, and -\exposid{next_} with \tcode{std::move(next)}. +Initializes \exposid{parent_} with \tcode{addressof(parent)} and +\exposid{inner_} with \tcode{std::move(inner)}. \end{itemdescr} \begin{itemdecl} -constexpr iterator_t base() const; +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{return \exposid{cur_};} +Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and +\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. \end{itemdescr} \begin{itemdecl} -constexpr value_type operator*() const; +constexpr decltype(auto) operator*() const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{return \{\exposid{cur_}, \exposid{next_}.begin()\};} +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_})...))}. \end{itemdescr} \begin{itemdecl} @@ -7471,24 +10266,23 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{cur_}@ = @\exposid{next_}@.begin(); -if (@\exposid{cur_}@ != ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { - @\exposid{cur_}@ = @\exposid{next_}@.end(); - if (@\exposid{cur_}@ == ranges::end(@\exposid{parent_}@->@\exposid{base_}@)) { - @\exposid{trailing_empty_}@ = true; - @\exposid{next_}@ = {@\exposid{cur_}@, @\exposid{cur_}@}; - } else { - @\exposid{next_}@ = @\exposid{parent_}@->@\exposid{find-next}@(@\exposid{cur_}@); - } -} else { - @\exposid{trailing_empty_}@ = false; -} +++@\exposid{inner_}@; return *this; \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{++*this}. +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -7503,7 +10297,7 @@ \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -7511,490 +10305,310 @@ \effects Equivalent to: \begin{codeblock} -return x.@\exposid{cur_}@ == y.@\exposid{cur_}@ && x.@\exposid{trailing_empty_}@ == y.@\exposid{trailing_empty_}@; +--@\exposid{inner_}@; +return *this; \end{codeblock} \end{itemdescr} -\rSec3[range.split.sentinel]{Class \tcode{split_view::\exposid{sentinel}}} - -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{forward_range}@ Pattern> - requires @\libconcept{view}@ && @\libconcept{view}@ && - @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> - struct split_view::@\exposid{sentinel}@ { - private: - sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos - - public: - @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(split_view& parent); - - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); - }; -} -\end{codeblock} - \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(split_view& parent); +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{ranges::end(parent.\exposid{base_})}. +Equivalent to: +\begin{codeblock} +auto tmp = *this; +--*this; +return tmp; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +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.\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 \libconcept{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.common]{Common view} - -\rSec3[range.common.overview]{Overview} - -\pnum -\tcode{common_view} takes a \libconcept{view} which has different types for -its iterator and sentinel and turns it into a \libconcept{view} of the same -elements with an iterator and sentinel of the same type. - -\pnum -\begin{note} -\tcode{common_view} is useful for calling legacy algorithms that expect -a range's iterator and sentinel types to be the same. -\end{note} - -\pnum -\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. - -\item Otherwise, \tcode{common_view\{E\}}. -\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()); - // ... -} -\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}% +Equivalent to: \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 - public: - common_view() requires @\libconcept{default_initializable}@ = default; - - constexpr explicit common_view(V r); - - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } - - 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_}@)); - } - - 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() { - if constexpr (@\libconcept{random_access_range}@ && @\libconcept{sized_range}@) - return ranges::begin(@\exposid{base_}@) + ranges::size(@\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::size(@\exposid{base_}@); - else - return common_iterator, sentinel_t>(ranges::end(@\exposid{base_}@)); - } +@\exposid{inner_}@ += x; +return *this; +\end{codeblock} +\end{itemdescr} - 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_}@); - } - }; +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} - template - common_view(R&&) -> common_view>; -} +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{inner_}@ -= x; +return *this; \end{codeblock} +\end{itemdescr} -\indexlibraryctor{common_view}% \begin{itemdecl} -constexpr explicit common_view(V base); +constexpr decltype(auto) operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)}. +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} \end{itemdescr} -\rSec2[range.reverse]{Reverse view} +\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}@>; +\end{itemdecl} -\rSec3[range.reverse.overview]{Overview} +\begin{itemdescr} +\pnum +Let \placeholder{op} be the operator. \pnum -\tcode{reverse_view} takes a bidirectional \libconcept{view} and produces -another \libconcept{view} that iterates the same elements in reverse order. +\effects +Equivalent to: +\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 @\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 -\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: -\begin{codeblock} -subrange(E.end().base(), E.begin().base()) -\end{codeblock} - \end{itemize} - However, in either case \tcode{E} is evaluated only once. -\item - Otherwise, equivalent to \tcode{reverse_view\{E\}}. -\end{itemize} +\effects +Equivalent to: +\tcode{return \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 @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} + +\begin{itemdescr} \pnum -\begin{example} -\begin{codeblock} -vector is {0,1,2,3,4}; -for (int i : is | views::reverse) - cout << i << ' '; // prints: 4 3 2 1 0 -\end{codeblock} -\end{example} +\effects +Equivalent to: +\tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} - n);} +\end{itemdescr} -\rSec3[range.reverse.view]{Class template \tcode{reverse_view}} +\begin{itemdecl} +friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\libconcept{sized_sentinel_for}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; +\end{itemdecl} -\indexlibraryglobal{reverse_view}% -\indexlibrarymember{base}{reverse_view}% -\indexlibrarymember{size}{reverse_view}% -\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; +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +\end{itemdescr} - constexpr explicit reverse_view(V r); +\rSec3[range.zip.transform.sentinel]{Class template \tcode{zip_transform_view::\exposid{sentinel}}} - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } +\indexlibraryglobal{zip_transform_view::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 + class zip_transform_view::@\exposid{sentinel}@ { + @\exposidnc{zentinel}@ @\exposid{inner_}@; // \expos + constexpr explicit @\exposidnc{sentinel}@(@\exposidnc{zentinel}@ inner); // \expos - constexpr reverse_iterator> begin(); - constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; - constexpr auto begin() const requires @\libconcept{common_range}@; + public: + @\exposid{sentinel}@() = default; + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) + requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; - constexpr reverse_iterator> end(); - constexpr auto end() const requires @\libconcept{common_range}@; + template + requires @\libconcept{sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); - constexpr auto size() requires @\libconcept{sized_range}@ { - return ranges::size(@\exposid{base_}@); - } + template + 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); - constexpr auto size() const requires @\libconcept{sized_range}@ { - return ranges::size(@\exposid{base_}@); - } + 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); }; - - template - reverse_view(R&&) -> reverse_view>; } \end{codeblock} -\indexlibraryctor{reverse_view}% \begin{itemdecl} -constexpr explicit reverse_view(V base); +constexpr explicit @\exposid{sentinel}@(@\exposid{zentinel}@ inner); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)}. +Initializes \exposid{inner_} with \tcode{inner}. \end{itemdescr} -\indexlibrarymember{begin}{reverse_view}% \begin{itemdecl} -constexpr reverse_iterator> begin(); +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) + requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\begin{codeblock} -make_reverse_iterator(ranges::next(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@))) -\end{codeblock} - -\pnum -\remarks -In order to provide the amortized constant time complexity required by -the \libconcept{range} concept, this function caches the result within the -\tcode{reverse_view} for use on subsequent calls. +\effects +Initializes \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. \end{itemdescr} -\indexlibrarymember{begin}{reverse_view}% \begin{itemdecl} -constexpr reverse_iterator> begin() requires @\libconcept{common_range}@; -constexpr auto begin() const requires @\libconcept{common_range}@; +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 \effects -Equivalent to: \tcode{return make_reverse_iterator(ranges::end(base_));} +Equivalent to: \tcode{return x.\exposid{inner_} == y.\exposid{inner_};} \end{itemdescr} -\indexlibrarymember{end}{reverse_view}% \begin{itemdecl} -constexpr reverse_iterator> end(); -constexpr auto end() const requires @\libconcept{common_range}@; +template + 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 make_reverse_iterator(ranges::begin(base_));} +Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} \end{itemdescr} -\rSec2[range.elements]{Elements view} - -\rSec3[range.elements.overview]{Overview} - -\pnum -\tcode{elements_view} takes -a \libconcept{view} of tuple-like values and a \tcode{size_t}, and -produces a \libconcept{view} with a value-type of the $N^\text{th}$ element -of the adapted \libconcept{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} -}; +\rSec2[range.adjacent]{Adjacent view} -auto names = historical_figures | views::elements<0>; -for (auto&& name : names) { - cout << name << ' '; // prints \tcode{Babbage Hamilton Lovelace Turing } -} +\rSec3[range.adjacent.overview]{Overview} -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 +\indexlibraryglobal{adjacent_view}% +\tcode{adjacent_view} takes a \libconcept{view} and +produces a \libconcept{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 -\tcode{keys_view} is an alias for \tcode{elements_view}, and -is useful for extracting keys from associative containers. +\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 +\tcode{((void)E, auto(views::empty>))} +if \tcode{N} is equal to \tcode{0}, +\item +otherwise, \tcode{adjacent_view, N>(E)}. +\end{itemize} \begin{example} \begin{codeblock} -auto names = historical_figures | views::keys; -for (auto&& name : names) { - cout << name << ' '; // prints \tcode{Babbage Hamilton Lovelace Turing } +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)} } \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} +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.elements.view]{Class template \tcode{elements_view}} +\rSec3[range.adjacent.view]{Class template \tcode{adjacent_view}} -\indexlibraryglobal{elements_view}% -\indexlibrarymember{base}{elements_view}% -\indexlibrarymember{begin}{elements_view}% -\indexlibrarymember{end}{elements_view}% -\indexlibrarymember{size}{elements_view}% +\indexlibrarymember{begin}{adjacent_view}% +\indexlibrarymember{end}{adjacent_view}% +\indexlibrarymember{size}{adjacent_view}% \begin{codeblock} namespace std::ranges { - template - concept @\defexposconcept{has-tuple-element}@ = // \expos - requires(T t) { - typename tuple_size::type; - requires N < tuple_size_v; - typename tuple_element_t; - { std::get(t) } -> @\libconcept{convertible_to}@&>; - }; - - template - concept @\defexposconcept{returnable-element}@ = // \expos - is_reference_v || 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_}@)); } + template<@\libconcept{forward_range}@ V, size_t N> + requires @\libconcept{view}@ && (N > 0) + class adjacent_view : public view_interface> { + V @\exposid{base_}@ = V(); // \expos - constexpr auto end() requires (!@\exposconcept{simple-view}@ && !@\libconcept{common_range}@) - { return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; } + // \ref{range.adjacent.iterator}, class template \tcode{adjacent_view::\exposid{iterator}} + template class @\exposidnc{iterator}@; // \expos - constexpr auto end() requires (!@\exposconcept{simple-view}@ && @\libconcept{common_range}@) - { return @\exposid{iterator}@{ranges::end(@\exposid{base_}@)}; } + // \ref{range.adjacent.sentinel}, class template \tcode{adjacent_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos - constexpr auto end() const requires @\libconcept{range}@ - { return @\exposid{sentinel}@{ranges::end(@\exposid{base_}@)}; } + struct @\exposidnc{as-sentinel}@{}; // \expos - constexpr auto end() const requires @\libconcept{common_range}@ - { return @\exposid{iterator}@{ranges::end(@\exposid{base_}@)}; } + public: + adjacent_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit adjacent_view(V base); - constexpr auto size() requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{base_}@); } + constexpr auto begin() requires (!@\exposconcept{simple-view}@) { + return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + } - constexpr auto size() const requires @\libconcept{sized_range}@ - { return ranges::size(@\exposid{base_}@); } + constexpr auto begin() const requires @\libconcept{range}@ { + return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + } - private: - // \ref{range.elements.iterator}, class template \tcode{elements_view::\exposid{iterator}} - template struct @\exposid{iterator}@; // \expos + 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}@(ranges::end(@\exposid{base_}@)); + } + } - // \ref{range.elements.sentinel}, class template \tcode{elements_view::\exposid{sentinel}} - template struct @\exposid{sentinel}@; // \expos + 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}@(ranges::end(@\exposid{base_}@)); + } + } - V @\exposid{base_}@ = V(); // \expos + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; }; } \end{codeblock} -\indexlibraryctor{elements_view}% \begin{itemdecl} -constexpr explicit elements_view(V base); +constexpr explicit adjacent_view(V base); \end{itemdecl} \begin{itemdescr} @@ -8003,43 +10617,51 @@ Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\rSec3[range.elements.iterator]{Class template \tcode{elements_view::\exposid{iterator}}} +\begin{itemdecl} +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; +\end{itemdecl} -\indexlibraryglobal{elements_view::iterator}% +\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 - - iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \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} - static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); // \expos +\rSec3[range.adjacent.iterator]{Class template \tcode{adjacent_view::\exposid{iterator}}} +\indexlibraryglobal{adjacent_view::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_concept = @\seebelow@; - using iterator_category = @\seebelow@; // not always present - using value_type = remove_cvref_t>>; + 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}@() requires @\libconcept{default_initializable}@> = default; - constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); + @\exposid{iterator}@() = 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 decltype(auto) operator*() const - { return @\exposid{get-element}@(@\exposid{current_}@); } - + 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}@>; @@ -8049,13 +10671,10 @@ 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}@>; + 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) @@ -8065,23 +10684,27 @@ 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}@>; - friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + 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 x, const @\exposid{iterator}@& y) + 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}@& x, difference_type y) + 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}@>; }; } \end{codeblock} \pnum -The member \grammarterm{typedef-name} \tcode{iterator_concept} -is defined as follows: +\tcode{\exposid{iterator}::iterator_concept} is defined as follows: \begin{itemize} \item If \exposid{Base} models \libconcept{random_access_range}, @@ -8090,96 +10713,55 @@ 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} - -\indexlibrarymember{\exposid{get-element}}{elements_view::iterator}% -\begin{itemdecl} -static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); // \expos -\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::iterator}% -\begin{itemdecl} -constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); -\end{itemdecl} +Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +\end{itemize} -\begin{itemdescr} \pnum -\effects -Initializes \exposid{current_} with \tcode{std::move(current)}. -\end{itemdescr} +If the invocation of any non-const member function of \exposid{iterator} +exits via an exception, the \exposid{iterator} acquires a singular value. -\indexlibraryctor{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> first, sentinel_t<@\exposid{Base}@> last); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +\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} -\indexlibrarymember{base}{elements_view::iterator}% \begin{itemdecl} -constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; +constexpr @\exposid{iterator}@(@\exposid{as-sentinel}@, iterator_t<@\exposid{Base}@> first, iterator_t<@\exposid{Base}@> last); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return \exposid{current_};} +\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} -\indexlibrarymember{base}{elements_view::iterator}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() &&; +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 std::move(\exposid{current_});} +Initializes each element of \exposid{current_} +with the corresponding element of \tcode{i.\exposid{current_}} as an xvalue. \end{itemdescr} -\indexlibrarymember{operator++}{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +constexpr auto operator*() const; \end{itemdecl} \begin{itemdescr} @@ -8187,25 +10769,31 @@ \effects Equivalent to: \begin{codeblock} -++@\exposid{current_}@; -return *this; +return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{elements_view::iterator}% \begin{itemdecl} -constexpr void operator++(int); +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{++\exposid{current_}}. +\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++}{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} \begin{itemdescr} @@ -8213,28 +10801,31 @@ \effects Equivalent to: \begin{codeblock} -auto temp = *this; -++@\exposid{current_}@; -return temp; +auto tmp = *this; +++*this; +return tmp; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator--}{elements_view::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} +\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--}{elements_view::iterator}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} @@ -8244,31 +10835,54 @@ \effects Equivalent to: \begin{codeblock} -auto temp = *this; ---@\exposid{current_}@; -return temp; +auto tmp = *this; +--*this; +return tmp; \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+=}{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type n); +constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{current_}@ += n; -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-=}{elements_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type n) +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}@>; \end{itemdecl} @@ -8277,24 +10891,20 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{current_}@ -= n; -return *this; +return @\exposid{tuple-transform}@([&](auto& i) -> decltype(auto) { return i[n]; }, @\exposid{current_}@); \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator==}{elements_view::iterator}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@<@\exposid{Base}@>; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} +\returns +\tcode{x.\exposid{current_}.back() == y.\exposid{current_}.back()}. \end{itemdescr} -\indexlibrarymember{operator<}{elements_view::iterator}% \begin{itemdecl} friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -8302,11 +10912,10 @@ \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_} < y.\exposid{current_};} +\returns +\tcode{x.\exposid{current_}.back() < y.\exposid{current_}.back()}. \end{itemdescr} -\indexlibrarymember{operator>}{elements_view::iterator}% \begin{itemdecl} friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -8318,7 +10927,6 @@ Equivalent to: \tcode{return y < x;} \end{itemdescr} -\indexlibrarymember{operator<=}{elements_view::iterator}% \begin{itemdecl} friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -8330,7 +10938,6 @@ Equivalent to: \tcode{return !(y < x);} \end{itemdescr} -\indexlibrarymember{operator>=}{elements_view::iterator}% \begin{itemdecl} friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -8342,88 +10949,126 @@ Equivalent to: \tcode{return !(x < y);} \end{itemdescr} -\indexlibrarymember{operator<=>}{elements_view::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}@>; + 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_};} +\returns +\tcode{x.\exposid{current_}.back() <=> y.\exposid{current_}.back()}. \end{itemdescr} -\indexlibrarymember{operator+}{elements_view::iterator}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) +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 iterator\{x\} += y;} +Equivalent to: +\begin{codeblock} +auto r = i; +r += n; +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator+}{elements_view::iterator}% \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) +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-}{elements_view::iterator}% \begin{itemdecl} -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{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return iterator\{x\} -= y;} +Equivalent to: +\tcode{return x.\exposid{current_}.back() - y.\exposid{current_}.back();} \end{itemdescr} -\indexlibrarymember{operator-}{elements_view::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}@>>; +friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{current_};} +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} \end{itemdescr} -\rSec3[range.elements.sentinel]{Class template \tcode{elements_view::\exposid{sentinel}}} +\begin{itemdecl} +friend constexpr void iter_swap(const @\exposid{iterator}@& l, const @\exposid{iterator}@& r) noexcept(@\seebelow@) + requires @\libconcept{indirectly_swappable}@>; +\end{itemdecl} -\indexlibraryglobal{elements_view::sentinel}% +\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} +\end{itemdescr} + +\rSec3[range.adjacent.sentinel]{Class template \tcode{adjacent_view::\exposid{sentinel}}} + +\indexlibraryglobal{adjacent_view::sentinel}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@ V, size_t N> - requires @\libconcept{view}@ && @\placeholder{has-tuple-element}@, N> && - @\placeholder{has-tuple-element}@>, N> && - @\exposconcept{returnable-element}@, N> + template<@\libconcept{forward_range}@ V, size_t N> + requires @\libconcept{view}@ && (N > 0) 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 + 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 explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) 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); @@ -8436,12 +11081,11 @@ 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); + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x); }; } \end{codeblock} -\indexlibraryctor{elements_view::sentinel}% \begin{itemdecl} constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); \end{itemdecl} @@ -8452,30 +11096,17 @@ Initializes \exposid{end_} with \tcode{end}. \end{itemdescr} -\indexlibraryctor{elements_view::sentinel}% \begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) 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::sentinel}% -\begin{itemdecl} -constexpr sentinel_t<@\exposid{Base}@> base() const; -\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==}{elements_view::sentinel}% \begin{itemdecl} template requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> @@ -8485,10 +11116,9 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{end_};} +Equivalent to: \tcode{return x.\exposid{current_}.back() == y.\exposid{end_};} \end{itemdescr} -\indexlibrarymember{operator-}{elements_view::sentinel}% \begin{itemdecl} template requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> @@ -8499,326 +11129,269 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_} - y.\exposid{end_};} +Equivalent to: \tcode{return x.\exposid{current_}.back() - y.\exposid{end_};} \end{itemdescr} -\indexlibrarymember{operator-}{elements_view::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); + 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 y.\exposid{end_} - x.\exposid{current_}.back();} \end{itemdescr} -\rSec2[range.zip]{Zip view} +\rSec2[range.adjacent.transform]{Adjacent transform view} -\rSec3[range.zip.overview]{Overview} +\rSec3[range.adjacent.transform.overview]{Overview} \pnum -\indexlibraryglobal{zip_view}% -\tcode{zip_view} takes any number of \libconcept{view}s and -produces a \libconcept{view} of tuples of references -to the corresponding elements of the constituent views. +\indexlibraryglobal{adjacent_transform_view}% +\tcode{adjacent_transform_view} takes an invocable object and +a \libconcept{view} and produces a \libconcept{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{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 +\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 -\tcode{auto(views::empty>)} -if \tcode{Es} is an empty pack, +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, \tcode{zip_view...>(Es...)}. +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}; -list l = {'a', 'b', 'c'}; - -auto z = views::zip(v, l); -range_reference_t f = z.front(); // \tcode{f} is a \tcode{pair} - // that refers to the first element of \tcode{v} and \tcode{l} +vector v = {1, 2, 3, 4}; -for (auto&& [x, y] : z) { - cout << '(' << x << ", " << y << ") "; // prints: (1, a) (2, b) +for (auto i : v | views::adjacent_transform<2>(std::multiplies())) { + cout << i << ' '; // prints \tcode{2 6 12} } \end{codeblock} \end{example} -\rSec3[range.zip.view]{Class template \tcode{zip_view}} +\rSec3[range.adjacent.transform.view]{Class template \tcode{adjacent_transform_view}} -\indexlibrarymember{begin}{zip_view}% -\indexlibrarymember{end}{zip_view}% -\indexlibrarymember{size}{zip_view}% +\indexlibrarymember{begin}{adjacent_transform_view}% +\indexlibrarymember{end}{adjacent_transform_view}% +\indexlibrarymember{size}{adjacent_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 - using @\exposid{tuple-or-pair}@ = @\seebelow@; // \expos - - template - constexpr auto @\exposid{tuple-transform}@(F&& f, Tuple&& tuple) { // \expos - return apply([&](Ts&&... elements) { - return @\exposid{tuple-or-pair}@...>( - invoke(f, std::forward(elements))... - ); - }, std::forward(tuple)); - } - - template - constexpr void @\exposid{tuple-for-each}@(F&& f, Tuple&& tuple) { // \expos - apply([&](Ts&&... elements) { - (invoke(f, std::forward(elements)), ...); - }, std::forward(tuple)); - } + 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 - template<@\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 0) - class zip_view : public view_interface> { - tuple @\exposid{views_}@; // \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.zip.iterator}, class template \tcode{zip_view::\exposid{iterator}} - template class @\exposidnc{iterator}@; // \expos + // \ref{range.adjacent.transform.iterator}, class template \tcode{adjacent_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.adjacent.transform.sentinel}, class template \tcode{adjacent_transform_view::\exposid{sentinel}} + template class @\exposidnc{sentinel}@; // \expos public: - zip_view() = default; - constexpr explicit zip_view(Views... views); + adjacent_transform_view() = default; + constexpr explicit adjacent_transform_view(V base, F fun); - constexpr auto begin() requires (!(@\exposconcept{simple-view}@ && ...)) { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::begin, @\exposid{views_}@)); + constexpr auto begin() { + return @\exposid{iterator}@(*this, @\exposid{inner_}@.begin()); } - constexpr auto begin() const requires (@\libconcept{range}@ && ...) { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::begin, @\exposid{views_}@)); + + 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 (!@\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{inner_}@.end()); } else { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + return @\exposid{sentinel}@(@\exposid{inner_}@.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}@, N)...> { + if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@(*this, @\exposid{inner_}@.end()); } else { - return @\exposid{iterator}@(@\exposid{tuple-transform}@(ranges::end, @\exposid{views_}@)); + 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(); + } - template - zip_view(Rs&&...) -> zip_view...>; + constexpr auto size() const requires @\libconcept{sized_range}@ { + return @\exposid{inner_}@.size(); + } + }; } \end{codeblock} -\pnum -Given some pack of types \tcode{Ts}, -the alias template \exposid{tuple-or-pair} is defined as follows: -\begin{itemize} -\item -If \tcode{sizeof...(Ts)} is 2, -\tcode{\exposid{tuple-or-pair}} denotes \tcode{pair}. -\item -Otherwise, \tcode{\exposid{tuple-or-pair}} denotes \tcode{tuple}. -\end{itemize} - -\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} - \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} -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{inner_} with \tcode{std::move(base)}. \end{itemdescr} -\rSec3[range.zip.iterator]{Class template \tcode{zip_view::\exposid{iterator}}} +\rSec3[range.adjacent.transform.iterator]{Class template \tcode{adjacent_transform_view::\exposid{iterator}}} -\indexlibraryglobal{zip_view::iterator}% +\indexlibraryglobal{adjacent_transform_view::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{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 zip_view::@\exposid{iterator}@ { - @\exposid{tuple-or-pair}@>...> @\exposid{current_}@;@\itcorr[-1]@ // \expos - constexpr explicit @\exposidnc{iterator}@(@\exposid{tuple-or-pair}@>...>); - // \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; // not always present - using iterator_concept = @\seebelow@; - using value_type = @\exposid{tuple-or-pair}@>...>; - using difference_type = common_type_t>...>; + 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{maybe-const}@>> && ...); - - 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}@; + requires Const && @\libconcept{convertible_to}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; - constexpr auto operator[](difference_type n) const - requires @\exposconcept{all-random-access}@; + 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}@>; - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires (@\libconcept{equality_comparable}@>> && ...); + 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); friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr auto operator<=>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@ && - (@\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 @\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{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 \tcode{\exposconcept{all-random-access}} is modeled, -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 an lvalue 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{\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_category} 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. \begin{itemdecl} -constexpr explicit @\exposid{iterator}@(@\exposid{tuple-or-pair}@>...> current); +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{inner-iterator}@ 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} \begin{itemdecl} constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && - (@\libconcept{convertible_to}@, iterator_t<@\exposid{maybe-const}@>> && ...); + requires Const && @\libconcept{convertible_to}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; \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} \begin{itemdecl} -constexpr auto operator*() const; +constexpr decltype(auto) operator*() const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -8826,7 +11399,17 @@ \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, (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} @@ -8839,23 +11422,13 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{tuple-for-each}@([](auto& i) { ++i; }, @\exposid{current_}@); +++@\exposid{inner_}@; return *this; \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr void operator++(int); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{++*this}. -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\exposconcept{all-forward}@; +constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} \begin{itemdescr} @@ -8870,7 +11443,7 @@ \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\exposconcept{all-bidirectional}@; +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -8878,13 +11451,13 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{tuple-for-each}@([](auto& i) { --i; }, @\exposid{current_}@); +--@\exposid{inner_}@; return *this; \end{codeblock} \end{itemdescr} \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} @@ -8899,8 +11472,7 @@ \end{itemdescr} \begin{itemdecl} -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}@>; \end{itemdecl} \begin{itemdescr} @@ -8908,14 +11480,13 @@ \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} \begin{itemdecl} -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}@>; \end{itemdecl} \begin{itemdescr} @@ -8923,14 +11494,14 @@ \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} \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} @@ -8938,569 +11509,258 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{tuple-transform}@([&](I& i) -> decltype(auto) { - return i[iter_difference_t(n)]; -}, @\exposid{current_}@); +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 bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires (@\libconcept{equality_comparable}@>> && ...); -\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 bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x.\exposid{current_} < y.\exposid{current_}}. -\end{itemdescr} - -\begin{itemdecl} + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return y < x;} -\end{itemdescr} - -\begin{itemdecl} + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\exposconcept{all-random-access}@; -\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 @\exposconcept{all-random-access}@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return !(x < y);} -\end{itemdescr} - -\begin{itemdecl} -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 -\returns -\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. -\end{itemdescr} - -\begin{itemdecl} -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: -\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 @\exposconcept{all-random-access}@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -auto r = i; -r -= n; -return r; -\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{maybe-const}@>> && ...); + 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 \tcode{\exposid{DIST}($i$)} be \tcode{difference_type(std::get<$i$>(x.\exposid{current_}) - std::get<$i$>(y.\exposid{current_}))}. +Let \placeholder{op} be the operator. \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_} \placeholder{op} y.\exposid{inner_};} \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}@>; +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: -\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} +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 @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \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} +Equivalent to: \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}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; +\end{itemdecl} +\begin{itemdescr} \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)}$. +\effects +Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} \end{itemdescr} -\rSec3[range.zip.sentinel]{Class template \tcode{zip_view::\exposid{sentinel}}} +\rSec3[range.adjacent.transform.sentinel]{Class template \tcode{adjacent_transform_view::\exposid{sentinel}}} -\indexlibraryglobal{zip_view::sentinel}% +\indexlibraryglobal{adjacent_transform_view::sentinel}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{input_range}@... Views> - requires (@\libconcept{view}@ && ...) && (sizeof...(Views) > 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 zip_view::@\exposid{sentinel}@ { - @\exposid{tuple-or-pair}@>...> @\exposid{end_}@;@\itcorr[-1]@ // \expos - constexpr explicit @\exposidnc{sentinel}@(@\exposid{tuple-or-pair}@>...> 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{maybe-const}@>> && ...); + 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 common_type_t>...> + 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 common_type_t>...> - 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} \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(@\exposid{tuple-or-pair}@>...> 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} \begin{itemdecl} constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && - (@\libconcept{convertible_to}@, sentinel_t<@\exposid{maybe-const}@>> && ...); + 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>> && ...) + 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 -\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}. +\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>...> + 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); -\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)}$. -\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{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 - y);} +Equivalent to \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} \end{itemdescr} -\rSec2[range.zip.transform]{Zip transform view} +\rSec2[range.chunk]{Chunk view} -\rSec3[range.zip.transform.overview]{Overview} +\rSec3[range.chunk.overview]{Overview} \pnum -\indexlibraryglobal{zip_transform_view}% -\tcode{zip_transform_view} takes an invocable object and -any number of \libconcept{view}s and -produces a \libconcept{view} -whose $M^\text{th}$ element is -the result of applying the invocable object -to the $M^\text{th}$ elements of all views. +\tcode{chunk_view} takes a \libconcept{view} and a number $N$ and +produces a range of \libconcept{view}s +that are $N$-sized non-overlapping successive chunks of +the elements of the original \libconcept{view}, in order. +The last \libconcept{view} in the range can have fewer than $N$ elements. \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}. -\begin{itemize} -\item -If \tcode{\libconcept{copy_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} +\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)}. -\pnum \begin{example} \begin{codeblock} -vector v1 = {1, 2}; -vector v2 = {4, 5, 6}; - -for (auto i : views::zip_transform(plus(), v1, v2)) { - cout << i << ' '; // prints: 5 7 -} -\end{codeblock} -\end{example} - -\rSec3[range.zip.transform.view]{Class template \tcode{zip_transform_view}} - -\indexlibrarymember{begin}{zip_transform_view}% -\indexlibrarymember{end}{zip_transform_view}% -\indexlibrarymember{size}{zip_transform_view}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{copy_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{copyable-box}@ @\exposid{fun_}@; // \expos - zip_view @\exposid{zip_}@; // \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.transform.iterator}, class template \tcode{zip_transform_view::\exposid{iterator}} - template class @\exposidnc{iterator}@; // \expos - - // \ref{range.zip.transform.sentinel}, class template \tcode{zip_transform_view::\exposid{sentinel}} - template class @\exposidnc{sentinel}@; // \expos - - public: - zip_transform_view() = default; - - 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() { - if constexpr (@\libconcept{common_range}@<@\exposid{InnerView}@>) { - return @\exposid{iterator}@(*this, @\exposid{zip_}@.end()); - } else { - return @\exposid{sentinel}@(@\exposid{zip_}@.end()); - } - } - - 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{sentinel}@(@\exposid{zip_}@.end()); - } - } - - 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(); - } - }; +vector v = {1, 2, 3, 4, 5}; - template - zip_transform_view(F, Rs&&...) -> zip_transform_view...>; +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} -\begin{itemdecl} -constexpr explicit zip_transform_view(F fun, Views... views); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{fun_} with \tcode{std::move(fun)} and -\exposid{zip_} with \tcode{std::move(views)...}. -\end{itemdescr} - -\rSec3[range.zip.transform.iterator]{Class template \tcode{zip_transform_view::\exposid{iterator}}} +\rSec3[range.chunk.view.input]{Class template \tcode{chunk_view} for input ranges} -\indexlibraryglobal{zip_transform_view::iterator}% +\indexlibrarymember{begin}{chunk_view}% +\indexlibrarymember{end}{chunk_view}% +\indexlibrarymember{size}{chunk_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{copy_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 - - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); // \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 difference_type = range_difference_t<@\exposid{Base}@>; + template + constexpr I @\exposidnc{div-ceil}@(I num, I denom) { // \expos + I r = num / denom; + if (num % denom) + ++r; + return r; + } - @\exposid{iterator}@() = default; - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; + 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 - constexpr decltype(auto) operator*() const noexcept(@\seebelow@); - constexpr @\exposid{iterator}@& operator++(); - constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; + @\exposid{non-propagating-cache}@> @\exposid{current_}@; // \expos - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; + // \ref{range.chunk.outer.iter}, class \tcode{chunk_view::\exposid{outer-iterator}} + class @\exposid{outer-iterator}@; // \expos - 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.inner.iter}, class \tcode{chunk_view::\exposid{inner-iterator}} + class @\exposid{inner-iterator}@; // \expos - constexpr decltype(auto) operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + public: + constexpr explicit chunk_view(V base, range_difference_t n); - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@<@\exposid{ziperator}@>; + constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } + constexpr V base() && { return std::move(@\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{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{ziperator}@>; + constexpr @\exposid{outer-iterator}@ begin(); + constexpr default_sentinel_t end() const noexcept; - 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{ziperator}@, @\exposid{ziperator}@>; + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; }; -} -\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}@>...> + template + chunk_view(R&& r, range_difference_t) -> chunk_view>; +} \end{codeblock} -is not an lvalue 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{(\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{itera\-tor_category} denotes \tcode{bidirectional_iterator_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} \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{ziperator}@ inner); +constexpr explicit chunk_view(V base, range_difference_t n); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{parent_} with \tcode{addressof(parent)} and -\exposid{inner_} with \tcode{std::move(inner)}. -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{ziperator}@, @\exposid{ziperator}@>; -\end{itemdecl} +\expects +\tcode{n > 0} is \tcode{true}. -\begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and -\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} \begin{itemdecl} -constexpr decltype(auto) operator*() const noexcept(@\seebelow@); +constexpr @\exposid{outer-iterator}@ begin(); \end{itemdecl} \begin{itemdescr} @@ -9508,20 +11768,25 @@ \effects Equivalent to: \begin{codeblock} -return apply([&](const auto&... iters) -> decltype(auto) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, *iters...); -}, @\exposid{inner_}@.@\exposid{current_}@); +@\exposid{current_}@ = ranges::begin(@\exposid{base_}@); +@\exposid{remainder_}@ = @\exposid{n_}@; +return @\exposid{outer-iterator}@(*this); \end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr default_sentinel_t end() const noexcept; +\end{itemdecl} +\begin{itemdescr} \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_})...))}. +\returns +\tcode{default_sentinel}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +constexpr auto size() requires @\libconcept{sized_range}@; +constexpr auto size() const requires @\libconcept{sized_range}@; \end{itemdecl} \begin{itemdescr} @@ -9529,68 +11794,101 @@ \effects Equivalent to: \begin{codeblock} -++@\exposid{inner_}@; -return *this; +return @\exposid{to-unsigned-like}@(@\exposidnc{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); \end{codeblock} \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} + \begin{itemdecl} -constexpr void operator++(int); +constexpr explicit @\exposid{outer-iterator}@(chunk_view& parent); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{++*this}. +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; +constexpr value_type operator*() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; -++*this; -return tmp; -\end{codeblock} +\expects +\tcode{*this == default_sentinel} is \tcode{false}. + +\pnum +\returns +\tcode{value_type(*\exposid{parent_})}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{outer-iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{*this == default_sentinel} is \tcode{false}. + \pnum \effects Equivalent to: \begin{codeblock} ---@\exposid{inner_}@; +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} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; ---*this; -return tmp; -\end{codeblock} +Equivalent to \tcode{++*this}. \end{itemdescr} -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} @@ -9598,14 +11896,13 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{inner_}@ += x; -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-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +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} @@ -9613,262 +11910,280 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{inner_}@ -= x; -return *this; +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 decltype(auto) operator[](difference_type n) const - requires @\libconcept{random_access_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::outer-iterator::value_type}% \begin{codeblock} -return apply([&](const Is&... iters) -> decltype(auto) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, iters[iter_difference_t(n)]...); -}, @\exposid{inner_}@.@\exposid{current_}@); +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} -\end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@<@\exposid{ziperator}@>; -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{ziperator}@>; +constexpr explicit value_type(chunk_view& parent); \end{itemdecl} \begin{itemdescr} -\pnum -Let \placeholder{op} be the operator. - \pnum \effects -Equivalent to: -\tcode{return x.\exposid{inner_} \placeholder{op} y.\exposid{inner_};} +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \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}@>; +constexpr @\exposid{inner-iterator}@ begin() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} + n);} +\returns +\tcode{\exposid{inner-iterator}(*\exposid{parent_})}. \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr default_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} - n);} +\returns +\tcode{default_sentinel}. \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}@>; +constexpr auto size() const + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: -\tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +\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.zip.transform.sentinel]{Class template \tcode{zip_transform_view::\exposid{sentinel}}} +\rSec3[range.chunk.inner.iter]{Class \tcode{chunk_view::\exposid{inner-iterator}}} -\indexlibraryglobal{zip_transform_view::sentinel}% +\indexlibraryglobal{chunk_view::inner-iterator}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{copy_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{sentinel}@ { - @\exposidnc{zentinel}@ @\exposid{inner_}@; // \expos - constexpr explicit @\exposidnc{sentinel}@(@\exposidnc{zentinel}@ inner); // \expos + 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: - @\exposid{sentinel}@() = default; - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; + using iterator_concept = input_iterator_tag; + using difference_type = range_difference_t; + using value_type = range_value_t; - template - requires @\libconcept{sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + @\exposid{inner-iterator}@(@\exposid{inner-iterator}@&&) = default; + @\exposid{inner-iterator}@& operator=(@\exposid{inner-iterator}@&&) = default; - template - 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); + constexpr const iterator_t& base() const &; - 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); + 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>; }; } \end{codeblock} \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(@\exposid{zentinel}@ inner); +constexpr explicit @\exposid{inner-iterator}@(chunk_view& parent) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{inner_} with \tcode{inner}. +Initializes \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{zentinel}@, @\exposid{zentinel}@>; +constexpr const iterator_t& base() const &; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. +Equivalent to: \tcode{return *\exposid{parent_}->\exposid{current_};} \end{itemdescr} \begin{itemdecl} -template - requires @\libconcept{sentinel_for}@<@\exposid{zentinel}@, @\exposid{ziperator}@> -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +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 x.\exposid{inner_} == y.\exposid{inner_};} +Equivalent to: \tcode{return **\exposid{parent_}->\exposid{current_};} \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{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); +constexpr @\exposid{inner-iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{*this == default_sentinel} is \tcode{false}. + \pnum \effects -Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +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} \end{itemdescr} -\rSec2[range.adjacent]{Adjacent view} - -\rSec3[range.adjacent.overview]{Overview} +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} +\begin{itemdescr} \pnum -\indexlibraryglobal{adjacent_view}% -\tcode{adjacent_view} takes a \libconcept{view} and -produces a \libconcept{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. +\effects +Equivalent to \tcode{++*this}. +\end{itemdescr} -\pnum -\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 -\tcode{((void)E, auto(views::empty>))} -if \tcode{N} is equal to \tcode{0}, -\item -otherwise, \tcode{adjacent_view, N>(E)}. -\end{itemize} +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); +\end{itemdecl} -\begin{example} -\begin{codeblock} -vector v = {1, 2, 3, 4}; +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{parent_}->\exposid{remainder_} == 0}. +\end{itemdescr} -for (auto i : v | views::adjacent<2>) { - cout << "(" << i.first << ", " << i.second << ") "; // prints: (1, 2) (2, 3) (3, 4) -} -\end{codeblock} -\end{example} +\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 -Define \tcode{\exposid{REPEAT}(T, N)} as a pack of \tcode{N} types, -each of which denotes the same type as \tcode{T}. +\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_}@); +\end{codeblock} +\end{itemdescr} -\rSec3[range.adjacent.view]{Class template \tcode{adjacent_view}} +\begin{itemdecl} +friend constexpr difference_type operator-(const @\exposid{inner-iterator}@& x, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; +\end{itemdecl} -\indexlibrarymember{begin}{adjacent_view}% -\indexlibrarymember{end}{adjacent_view}% -\indexlibrarymember{size}{adjacent_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 +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return -(y - x);} +\end{itemdescr} - // \ref{range.adjacent.iterator}, class template \tcode{adjacent_view::\exposid{iterator}} - template class @\exposidnc{iterator}@; // \expos +\rSec3[range.chunk.view.fwd]{Class template \tcode{chunk_view} for forward ranges} - // \ref{range.adjacent.sentinel}, class template \tcode{adjacent_view::\exposid{sentinel}} - template class @\exposidnc{sentinel}@; // \expos +\indexlibrarymember{begin}{chunk_view}% +\indexlibrarymember{end}{chunk_view}% +\indexlibrarymember{size}{chunk_view}% +\begin{codeblock} +namespace std::ranges { + template<@\libconcept{view}@ V> + requires @\libconcept{forward_range}@ + class chunk_view : public view_interface> { + V @\exposid{base_}@; // \expos + range_difference_t @\exposid{n_}@; // \expos - struct @\exposidnc{as-sentinel}@{}; // \expos + // \ref{range.chunk.fwd.iter}, class template \tcode{chunk_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos public: - adjacent_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit adjacent_view(V base); + 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 auto begin() requires (!@\exposconcept{simple-view}@) { - return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + return @\exposid{iterator}@(this, ranges::begin(@\exposid{base_}@)); } - constexpr auto begin() const requires @\libconcept{range}@ { - return @\exposid{iterator}@(ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + 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}@) { - return @\exposid{iterator}@(@\exposid{as-sentinel}@{}, ranges::begin(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); + 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 @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); + return default_sentinel; } } - 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{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 @\exposid{sentinel}@(ranges::end(@\exposid{base_}@)); + return default_sentinel; } } @@ -9879,13 +12194,18 @@ \end{codeblock} \begin{itemdecl} -constexpr explicit adjacent_view(V base); +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)}. +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{n_} with \tcode{n}. \end{itemdescr} \begin{itemdecl} @@ -9898,39 +12218,44 @@ \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); +return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); \end{codeblock} \end{itemdescr} -\rSec3[range.adjacent.iterator]{Class template \tcode{adjacent_view::\exposid{iterator}}} +\rSec3[range.chunk.fwd.iter]{Class template \tcode{chunk_view::\exposid{iterator}} for forward ranges} -\indexlibraryglobal{adjacent_view::iterator}% +\indexlibraryglobal{chunk_view::iterator}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, size_t N> - requires @\libconcept{view}@ && (N > 0) + template<@\libconcept{view}@ V> + requires @\libconcept{forward_range}@ 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 chunk_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{n_}@ = 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: using iterator_category = input_iterator_tag; - using iterator_concept = @\seebelow@; - using value_type = @\exposid{tuple-or-pair}@<@\exposid{REPEAT}@(range_value_t<@\exposid{Base}@>, N)...>; + 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}@>; @\exposid{iterator}@() = default; constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> + && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; - constexpr auto operator*() const; + constexpr iterator_t<@\exposid{Base}@> base() const; + + constexpr value_type operator*() const; constexpr @\exposid{iterator}@& operator++(); constexpr @\exposid{iterator}@ operator++(int); @@ -9942,10 +12267,12 @@ constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - constexpr auto operator[](difference_type n) const + constexpr value_type 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}@>; friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) @@ -9967,9 +12294,10 @@ 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}@>; + 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} @@ -9987,61 +12315,57 @@ 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}@> first, sentinel_t<@\exposid{Base}@> last); +constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, + range_difference_t<@\exposid{Base}@> missing = 0); \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}. +\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} \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{as-sentinel}@, iterator_t<@\exposid{Base}@> first, iterator_t<@\exposid{Base}@> last); +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 -\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{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} \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +constexpr iterator_t<@\exposid{Base}@> base() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes each element of \exposid{current_} -with the corresponding element of \tcode{i.\exposid{current_}} as an xvalue. +\returns +\exposid{current_}. \end{itemdescr} \begin{itemdecl} -constexpr auto operator*() const; +constexpr value_type 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} +\expects +\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. + +\pnum +\returns +\tcode{views::take(subrange(\exposid{current_}, \exposid{end_}), \exposid{n_})}. \end{itemdescr} \begin{itemdecl} @@ -10051,16 +12375,15 @@ \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. +\tcode{\exposid{current_} != \exposid{end_}} is \tcode{true}. \pnum -\returns -\tcode{*this}. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@, @\exposid{end_}@); +return *this; +\end{codeblock} \end{itemdescr} \begin{itemdecl} @@ -10069,7 +12392,7 @@ \begin{itemdescr} \pnum -\expects +\effects Equivalent to: \begin{codeblock} auto tmp = *this; @@ -10084,17 +12407,13 @@ \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}. +\effects +Equivalent to: +\begin{codeblock} +ranges::advance(@\exposid{current_}@, @\exposid{missing_}@ - @\exposid{n_}@); +@\exposid{missing_}@ = 0; +return *this; +\end{codeblock} \end{itemdescr} \begin{itemdecl} @@ -10120,16 +12439,25 @@ \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. +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} \pnum -\returns -\tcode{*this}. +\effects +Equivalent to: +\begin{codeblock} +if (x > 0) { + @\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * x, @\exposid{end_}@); +} else if (x < 0) { + ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * x + @\exposid{missing_}@); + @\exposid{missing_}@ = 0; +} +return *this; +\end{codeblock} \end{itemdescr} \begin{itemdecl} @@ -10139,41 +12467,39 @@ \begin{itemdescr} \pnum -\expects -\tcode{\exposid{current_}.front() - x} has well-defined behavior. +\effects +Equivalent to: \tcode{return *this += -x;} +\end{itemdescr} -\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. +\begin{itemdecl} +constexpr value_type operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} +\begin{itemdescr} \pnum \returns -\tcode{*this}. +\tcode{*(*this + n)}. \end{itemdescr} \begin{itemdecl} -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); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -return @\exposid{tuple-transform}@([&](auto& i) -> decltype(auto) { return i[n]; }, @\exposid{current_}@); -\end{codeblock} +\returns +\tcode{x.\exposid{current_} == y.\exposid{current_}}. \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{current_}.back() == y.\exposid{current_}.back()}. +\tcode{x.\exposid{current_} == x.\exposid{end_}}. \end{itemdescr} \begin{itemdecl} @@ -10184,7 +12510,7 @@ \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{current_}.back() < y.\exposid{current_}.back()}. +\tcode{x.\exposid{current_} < y.\exposid{current_}}. \end{itemdescr} \begin{itemdecl} @@ -10229,7 +12555,7 @@ \begin{itemdescr} \pnum \returns -\tcode{x.\exposid{current_}.back() <=> y.\exposid{current_}.back()}. +\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. \end{itemdescr} \begin{itemdecl} @@ -10273,316 +12599,278 @@ \begin{itemdescr} \pnum -\effects -Equivalent to: -\tcode{return x.\exposid{current_}.back() - y.\exposid{current_}.back();} +\returns +\tcode{(x.\exposid{current_} - y.\exposid{current_} + x.\exposid{missing_} - y.\exposid{missing_}) / x.\exposid{n_}}. \end{itemdescr} \begin{itemdecl} -friend constexpr auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); +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 -\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} +\returns +\tcode{\exposid{div-ceil}(x.\exposid{end_} - x.\exposid{current_}, x.\exposid{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, default_sentinel_t y) + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; \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_}}. +\effects +Equivalent to: \tcode{return -(y - x);} +\end{itemdescr} + +\rSec2[range.slide]{Slide view} + +\rSec3[range.slide.overview]{Overview} \pnum -\effects -For every integer $0 \leq i < \tcode{N}$, -performs -\tcode{ranges::iter_swap(l.\exposid{current_}[$i$], r.\exposid{current_}[$i$])}. +\tcode{slide_view} takes a \libconcept{view} and a number $N$ and +produces a \libconcept{view} +whose $M^\text{th}$ element is a \libconcept{view} over +the $M^\text{th}$ through +$(M + N - 1)^\text{th}$ elements +of the original \libconcept{view}. +If the original \libconcept{view} has fewer than $N$ elements, +the resulting \libconcept{view} is empty. \pnum -\remarks -The exception specification is equivalent to: +\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} -noexcept(ranges::iter_swap(declval>(), declval>())) +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{itemdescr} +\end{example} -\rSec3[range.adjacent.sentinel]{Class template \tcode{adjacent_view::\exposid{sentinel}}} +\rSec3[range.slide.view]{Class template \tcode{slide_view}} -\indexlibraryglobal{adjacent_view::sentinel}% +\indexlibrarymember{begin}{slide_view}% +\indexlibrarymember{end}{slide_view}% +\indexlibrarymember{size}{slide_view}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, size_t N> - requires @\libconcept{view}@ && (N > 0) - 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 + template + concept @\defexposconcept{slide-caches-nothing}@ = @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; // \expos - public: - @\exposid{sentinel}@() = default; - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; + template + concept @\defexposconcept{slide-caches-last}@ = // \expos + !@\exposconcept{slide-caches-nothing}@ && @\libconcept{bidirectional_range}@ && @\libconcept{common_range}@; - template - requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + template + concept @\defexposconcept{slide-caches-first}@ = // \expos + !@\exposconcept{slide-caches-nothing}@ && !@\exposconcept{slide-caches-last}@; - 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<@\libconcept{forward_range}@ V> + requires @\libconcept{view}@ + class slide_view : public view_interface> { + V @\exposid{base_}@; // \expos + range_difference_t @\exposid{n_}@; // \expos - 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); - }; -} -\end{codeblock} + // \ref{range.slide.iterator}, class template \tcode{slide_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos -\begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); -\end{itemdecl} + // \ref{range.slide.sentinel}, class \tcode{slide_view::\exposid{sentinel}} + class @\exposid{sentinel}@; // \expos -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{end_} with \tcode{end}. -\end{itemdescr} + public: + constexpr explicit slide_view(V base, range_difference_t n); -\begin{itemdecl} -constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; -\end{itemdecl} + constexpr auto begin() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); + constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{end_} with \tcode{std::move(i.\exposid{end_})}. -\end{itemdescr} + constexpr auto end() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); + constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; -\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} + constexpr auto size() requires @\libconcept{sized_range}@; + constexpr auto size() const requires @\libconcept{sized_range}@; + }; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return x.\exposid{current_}.back() == y.\exposid{end_};} -\end{itemdescr} + template + slide_view(R&& r, range_difference_t) -> slide_view>; +} +\end{codeblock} \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 explicit slide_view(V base, range_difference_t n); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{n > 0} is \tcode{true}. + \pnum \effects -Equivalent to: \tcode{return x.\exposid{current_}.back() - y.\exposid{end_};} +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{n_} with \tcode{n}. \end{itemdescr} \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 auto begin() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return y.\exposid{end_} - x.\exposid{current_}.back();} -\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 \libconcept{view} and produces a \libconcept{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}: +\returns \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. +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, -the expression \tcode{views::adjacent_transform(E, F)} is -expression-equivalent to -\tcode{adja\-cent_transform_view, decay_t, N>(E, F)}. +Otherwise, \tcode{\exposid{iterator}(ranges::begin(\exposid{base_}), \exposid{n_})}. \end{itemize} \pnum -\begin{example} -\begin{codeblock} -vector v = {1, 2, 3, 4}; - -for (auto i : v | views::adjacent_transform<2>(std::multiplies())) { - cout << i << ' '; // prints: 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}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{copy_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{copyable-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 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()); - } +\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} - constexpr auto end() { - if constexpr (@\libconcept{common_range}@<@\exposid{InnerView}@>) { - return @\exposid{iterator}@(*this, @\exposid{inner_}@.end()); - } else { - return @\exposid{sentinel}@(@\exposid{inner_}@.end()); - } - } +\begin{itemdecl} +constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; +\end{itemdecl} - 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()); - } - } +\begin{itemdescr} +\pnum +\returns +\tcode{\exposid{iterator}(ranges::begin(\exposid{base_}), \exposid{n_})}. +\end{itemdescr} - constexpr auto size() requires @\libconcept{sized_range}@<@\exposid{InnerView}@> { - return @\exposid{inner_}@.size(); - } +\begin{itemdecl} +constexpr auto end() + requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); +\end{itemdecl} - constexpr auto size() const requires @\libconcept{sized_range}@ { - return @\exposid{inner_}@.size(); - } - }; -} +\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} \begin{itemdecl} -constexpr explicit adjacent_transform_view(V base, F fun); +constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{begin() + range_difference_t(size())}. +\end{itemdescr} + +\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{fun_} with \tcode{std::move(fun)} and -\exposid{inner_} with \tcode{std::move(base)}. +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} -\rSec3[range.adjacent.transform.iterator]{Class template \tcode{adjacent_transform_view::\exposid{iterator}}} +\rSec3[range.slide.iterator]{Class template \tcode{slide_view::\exposid{iterator}}} -\indexlibraryglobal{adjacent_transform_view::iterator}% +\indexlibraryglobal{slide_view::iterator}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{copy_constructible}@ F, size_t N> - requires @\libconcept{view}@ && (N > 0) && is_object_v && - @\libconcept{regular_invocable}@, N)...> && - @\exposconcept{can-reference}@, N)...>> + template<@\libconcept{forward_range}@ V> + requires @\libconcept{view}@ 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 + 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 \tcode{\exposid{Base}} models \tcode{\exposconcept{slide-caches-first}} + range_difference_t<@\exposid{Base}@> @\exposid{n_}@ = 0; // \expos - constexpr @\exposidnc{iterator}@(@\exposidnc{Parent}@& parent, @\exposidnc{inner-iterator}@ inner); // \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}@(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 = @\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 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}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; + 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 @\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 decltype(auto) operator[](difference_type n) const + 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}@>; 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) @@ -10592,7 +12880,8 @@ 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}@>; + 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}@>; @@ -10601,178 +12890,103 @@ 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}@>; + requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; }; } \end{codeblock} \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 an lvalue reference, -\tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\item -Otherwise, let \tcode{C} denote the type -\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{ran\-dom_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_category} 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} -\begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, @\exposid{inner-iterator}@ inner); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{parent_} with \tcode{addressof(parent)} and -\exposid{inner_} with \tcode{std::move(inner)}. -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{inner-iterator}@, @\exposid{inner-iterator}@>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and -\exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. -\end{itemdescr} - -\begin{itemdecl} -constexpr decltype(auto) operator*() const noexcept(@\seebelow@); -\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, (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} +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}@& operator++(); +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 -Equivalent to: -\begin{codeblock} -++@\exposid{inner_}@; -return *this; -\end{codeblock} +Initializes \exposid{current_} with \tcode{current} and +\exposid{n_} with \tcode{n}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +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 -Equivalent to: -\begin{codeblock} -auto tmp = *this; -++*this; -return tmp; -\end{codeblock} +Initializes \exposid{current_} with \tcode{current}, +\exposid{last_ele_} with \tcode{last_ele}, and +\exposid{n_} with \tcode{n}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +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} ---@\exposid{inner_}@; -return *this; -\end{codeblock} +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 @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr auto operator*() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; ---*this; -return tmp; -\end{codeblock} +\returns +\tcode{views::counted(\exposid{current_}, \exposid{n_})}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{inner_}@ += x; -return *this; -\end{codeblock} -\end{itemdescr} +\expects +\exposid{current_} and \exposid{last_ele_} (if present) are incrementable. -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; -\end{itemdecl} +\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. -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{inner_}@ -= x; -return *this; -\end{codeblock} +\returns +\tcode{*this}. \end{itemdescr} \begin{itemdecl} -constexpr decltype(auto) operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@ operator++(int); \end{itemdecl} \begin{itemdescr} @@ -10780,285 +12994,175 @@ \effects Equivalent to: \begin{codeblock} -return apply([&](const auto&... iters) -> decltype(auto) { - return invoke(*@\exposid{parent_}@->@\exposid{fun_}@, iters[n]...); -}, @\exposid{inner_}@.@\exposid{current_}@); +auto tmp = *this; +++*this; +return tmp; \end{codeblock} \end{itemdescr} \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}@>; +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -Let \placeholder{op} be the operator. +\expects +\exposid{current_} and \exposid{last_ele_} (if present) are decrementable. \pnum -\effects -Equivalent to: \tcode{return x.\exposid{inner_} \placeholder{op} y.\exposid{inner_};} +\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} \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--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} + n);} +Equivalent to: +\begin{codeblock} +auto tmp = *this; +--*this; +return tmp; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) +constexpr @\exposid{iterator}@& operator+=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return \exposid{iterator}(*i.\exposid{parent_}, i.\exposid{inner_} - n);} -\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} -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} +\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 -\effects -Equivalent to: \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +\returns +\tcode{*this}. \end{itemdescr} -\rSec3[range.adjacent.transform.sentinel]{Class template \tcode{adjacent_transform_view::\exposid{sentinel}}} - -\indexlibraryglobal{adjacent_transform_view::sentinel}% -\begin{codeblock} -namespace std::ranges { - template<@\libconcept{forward_range}@ V, @\libconcept{copy_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 - - public: - @\exposid{sentinel}@() = default; - constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{inner-sentinel}@, @\exposid{inner-sentinel}@>; - - template - 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}@<@\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{codeblock} - \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(@\exposid{inner-sentinel}@ inner); +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{inner_} with \tcode{inner}. -\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 @\exposid{sentinel}@(@\exposid{sentinel}@ i) - requires Const && @\libconcept{convertible_to}@<@\exposid{inner-sentinel}@, @\exposid{inner-sentinel}@>; -\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 -\effects -Initializes \exposid{inner_} with \tcode{std::move(i.\exposid{inner_})}. +\returns +\tcode{*this}. \end{itemdescr} \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 operator[](difference_type n) const + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{return x.\exposid{inner_} == y.\exposid{inner_};} +Equivalent to: \tcode{return views::counted(\exposid{current_} + n, \exposid{n_});} \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); +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{return x.\exposid{inner_} - y.\exposid{inner_};} +\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} -\rSec2[range.chunk]{Chunk view} - -\rSec3[range.chunk.overview]{Overview} - -\pnum -\tcode{chunk_view} takes a \libconcept{view} and a number \tcode{N} and -produces a range of \libconcept{view}s -that are \tcode{N}-sized non-overlapping successive chunks of -the elements of the original \libconcept{view}, in order. -The last \libconcept{view} in the range can have fewer than \tcode{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 << "] "; -} -\end{codeblock} -The above prints: \tcode{[1, 2] [3, 4] [5]} -\end{example} - -\rSec3[range.chunk.view.input]{\tcode{chunk_view} for input ranges} - -\indexlibrarymember{begin}{chunk_view}% -\indexlibrarymember{end}{chunk_view}% -\indexlibrarymember{size}{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_}@ = V(); // \expos - range_difference_t @\exposid{n_}@ = 0; // \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: - chunk_view() requires @\libconcept{default_initializable}@ = default; - 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() noexcept; - - 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} - template - chunk_view(R&& r, range_difference_t) -> chunk_view>; -} -\end{codeblock} +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_} < y.\exposid{current_}}. +\end{itemdescr} \begin{itemdecl} -constexpr explicit chunk_view(V base, range_difference_t n); +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{n > 0} is \tcode{true}. +\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 -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{n_} with \tcode{n}. +Equivalent to: \tcode{return !(y < x);} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{outer-iterator}@ begin(); +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} -current_ = ranges::begin(base_); -remainder_ = n_; -return @\exposid{outer-iterator}@(*this); -\end{codeblock} +Equivalent to: \tcode{return !(x < y);} \end{itemdescr} \begin{itemdecl} -constexpr default_sentinel_t end() noexcept; +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{default_sentinel}. +\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. \end{itemdescr} \begin{itemdecl} -constexpr auto size() requires @\libconcept{sized_range}@; -constexpr auto size() const requires @\libconcept{sized_range}@; +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} @@ -11066,197 +13170,232 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{to-unsigned-like}@(@\exposidnc{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); +auto r = i; +r += n; +return r; \end{codeblock} \end{itemdescr} -\rSec3[range.chunk.outer.iter]{Class \tcode{chunk_view::\exposid{outer-iterator}}} +\begin{itemdecl} +friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) + requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +\end{itemdecl} -\indexlibraryglobal{chunk_view::outer-iterator}% +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{input_range}@ - class chunk_view::@\exposid{outer-iterator}@ { - chunk_view* @\exposid{parent_}@; // \expos +auto r = i; +r -= n; +return r; +\end{codeblock} +\end{itemdescr} - constexpr explicit @\exposid{outer-iterator}@(chunk_view& parent); // \expos +\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} - public: - using iterator_concept = input_iterator_tag; - using difference_type = range_difference_t; +\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} - // \ref{range.chunk.outer.value}, class \tcode{chunk_view::\exposid{outer-iterator}::value_type} - struct value_type; +\rSec3[range.slide.sentinel]{Class \tcode{slide_view::\exposid{sentinel}}} - @\exposid{outer-iterator}@(@\exposid{outer-iterator}@&&) = default; - @\exposid{outer-iterator}@& operator=(@\exposid{outer-iterator}@&&) = default; +\indexlibraryglobal{chunk_view::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 - constexpr value_type operator*() const; - constexpr @\exposid{outer-iterator}@& operator++(); - constexpr void operator++(int); + public: + @\exposid{sentinel}@() = default; - friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); - 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>; + 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} + \begin{itemdecl} -constexpr explicit @\exposid{outer-iterator}@(chunk_view& parent); +constexpr explicit @\exposid{sentinel}@(sentinel_t end); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}. +Initializes \exposid{end_} with \tcode{end}. \end{itemdescr} \begin{itemdecl} -constexpr value_type operator*() const; +friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{*this == default_sentinel} is \tcode{false}. - \pnum \returns -\tcode{value_type(*\exposid{parent_})}. +\tcode{x.\exposid{last_ele_} == y.\exposid{end_}}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{outer-iterator}@& operator++(); +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 -\expects -\tcode{*this == default_sentinel} is \tcode{false}. - -\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_}@; -return *this; -\end{codeblock} +\returns +\tcode{x.\exposid{last_ele_} - y.\exposid{end_}}. \end{itemdescr} \begin{itemdecl} -constexpr void operator++(int); +friend constexpr range_difference_t + operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x) + requires @\libconcept{sized_sentinel_for}@, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{++*this}. +\returns +\tcode{y.\exposid{end_} - x.\exposid{last_ele_}}. \end{itemdescr} -\begin{itemdecl} -friend constexpr bool operator==(const @\exposid{outer-iterator}@& x, default_sentinel_t); -\end{itemdecl} +\rSec2[range.chunk.by]{Chunk by view} -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return *x.@\exposid{parent_}@->@\exposid{current_}@ == ranges::end(x.@\exposid{parent_}@->@\exposid{base_}@) && x.@\exposid{parent_}@->@\exposid{remainder_}@ != 0; -\end{codeblock} -\end{itemdescr} +\rSec3[range.chunk.by.overview]{Overview} -\begin{itemdecl} -friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{outer-iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; -\end{itemdecl} +\pnum +\tcode{chunk_by_view} takes a \libconcept{view} and a predicate, and +splits the \libconcept{view} into \tcode{subrange}s +between each pair of adjacent elements +for which the predicate returns \tcode{false}. -\begin{itemdescr} \pnum -\effects -Equivalent to: +\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} -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; +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 << "] "; } -return @\exposidnc{div-ceil}@(dist - x.@\exposid{parent_}@->@\exposid{remainder_}@, x.@\exposid{parent_}@->@\exposid{n_}@) + 1; +// The above prints \tcode{[1, 2, 2, 3] [0, 4, 5] [2]} \end{codeblock} -\end{itemdescr} - -\begin{itemdecl} -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: \tcode{return -(y - x);} -\end{itemdescr} +\end{example} -\rSec3[range.chunk.outer.value]{Class \tcode{chunk_view::\exposid{outer-iterator}::value_type}} +\rSec3[range.chunk.by.view]{Class template \tcode{chunk_by_view}} -\indexlibraryglobal{chunk_view::outer-iterator::value_type}% \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 + 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_}@ = Pred(); // \expos - constexpr explicit value_type(chunk_view& parent); // \expos + // \ref{range.chunk.by.iter}, class \tcode{chunk_by_view::\exposid{iterator}} + class @\exposidnc{iterator}@; // \expos public: - constexpr @\exposid{inner-iterator}@ begin() const noexcept; - constexpr default_sentinel_t end() const noexcept; + chunk_by_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; + constexpr explicit chunk_by_view(V base, Pred pred); - constexpr auto size() const - requires @\libconcept{sized_sentinel_for}@, iterator_t>; + 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} \begin{itemdecl} -constexpr explicit value_type(chunk_view& parent); +constexpr explicit chunk_by_view(V base, Pred pred); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}. +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{pred_} with \tcode{std::move(pred)}. \end{itemdescr} +\indexlibrarymember{pred}{chunk_by_view}% \begin{itemdecl} -constexpr @\exposid{inner-iterator}@ begin() const noexcept; +constexpr const Pred& pred() const; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{\exposid{inner-iterator}(*\exposid{parent_})}. +\effects +Equivalent to: \tcode{return *\exposid{pred_};} \end{itemdescr} \begin{itemdecl} -constexpr default_sentinel_t end() const noexcept; +constexpr @\exposid{iterator}@ begin(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. + \pnum \returns -\tcode{default_sentinel}. +\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} \begin{itemdecl} -constexpr auto size() const - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +constexpr auto end(); \end{itemdecl} \begin{itemdescr} @@ -11264,125 +13403,181 @@ \effects Equivalent to: \begin{codeblock} -return ranges::min(@\exposid{parent_}@->@\exposid{remainder_}@, ranges::end(@\exposid{parent_}@->@\exposid{base_}@) - *@\exposid{parent_}@->@\exposid{current_}@); +if constexpr (@\libconcept{common_range}@) { + return @\exposid{iterator}@(*this, ranges::end(@\exposid{base_}@), ranges::end(@\exposid{base_}@)); +} else { + return default_sentinel; +} +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr iterator_t @\exposid{find-next}@(iterator_t current); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. + +\pnum +\returns +\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} -\rSec3[range.chunk.inner.iter]{Class \tcode{chunk_view::\exposid{inner-iterator}}} +\begin{itemdecl} +constexpr iterator_t @\exposid{find-prev}@(iterator_t current) requires @\libconcept{bidirectional_range}@; +\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} + +\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}}} -\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 + 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 explicit @\exposid{inner-iterator}@(chunk_view& parent) noexcept; // \expos + constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, // \expos + iterator_t next); 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; + using value_type = subrange>; + using difference_type = range_difference_t; + using iterator_category = input_iterator_tag; + using iterator_concept = @\seebelow@; - constexpr const iterator_t& base() const &; + @\exposid{iterator}@() = default; - constexpr range_reference_t operator*() const; - constexpr @\exposid{inner-iterator}@& operator++(); - constexpr void operator++(int); + constexpr value_type operator*() const; + constexpr @\exposid{iterator}@& operator++(); + constexpr @\exposid{iterator}@ operator++(int); - friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; - 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 bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); + friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); }; } \end{codeblock} -\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} +\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} \begin{itemdecl} -constexpr const iterator_t& base() const &; +constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, iterator_t next); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *\exposid{parent_}->\exposid{current_};} +Initializes \exposid{parent_} with \tcode{addressof(parent)}, +\exposid{current_} with \tcode{current}, and +\exposid{next_} with \tcode{next}. \end{itemdescr} \begin{itemdecl} -constexpr range_reference_t operator*() const; +constexpr value_type operator*() const; \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{*this == default_sentinel} is \tcode{false}. +\exposid{current_} is not equal to \exposid{next_}. \pnum -\effects -Equivalent to: \tcode{return **\exposid{parent_}->\exposid{current_};} +\returns +\tcode{subrange(\exposid{current_}, \exposid{next_})}. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{inner-iterator}@& operator++(); +constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{*this == default_sentinel} is \tcode{false}. +\exposid{current_} is not equal to \exposid{next_}. \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_}@; +@\exposid{current_}@ = @\exposid{next_}@; +@\exposid{next_}@ = @\exposid{parent_}@->@\exposid{find-next}@(@\exposid{current_}@); return *this; \end{codeblock} \end{itemdescr} \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} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{inner-iterator}@& x, default_sentinel_t); +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{parent_}->\exposid{remainder_} == 0}. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{next_}@ = @\exposid{current_}@; +@\exposid{current_}@ = @\exposid{parent_}@->@\exposid{find-prev}@(@\exposid{next_}@); +return *this; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -friend constexpr difference_type operator-(default_sentinel_t y, const @\exposid{inner-iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; \end{itemdecl} \begin{itemdescr} @@ -11390,56 +13585,87 @@ \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 tmp = *this; +--*this; +return tmp; \end{codeblock} \end{itemdescr} \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 bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return -(y - x);} +\returns +\tcode{x.\exposid{current_} == y.\exposid{current_}}. \end{itemdescr} -\rSec3[range.chunk.view.fwd]{\tcode{chunk_view} for forward ranges} +\begin{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +\end{itemdecl} -\indexlibrarymember{begin}{chunk_view}% -\indexlibrarymember{end}{chunk_view}% -\indexlibrarymember{size}{chunk_view}% +\begin{itemdescr} +\pnum +\returns +\tcode{x.\exposid{current_} == x.\exposid{next_}}. +\end{itemdescr} + +\rSec2[range.stride]{Stride view} + +\rSec3[range.stride.overview]{Overview} + +\pnum +\tcode{stride_view} presents a \libconcept{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} -namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{forward_range}@ - class chunk_view : public view_interface> { - V @\exposid{base_}@ = V(); // \expos - range_difference_t @\exposid{n_}@ = 0; // \expos +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} - // \ref{range.chunk.fwd.iter}, class template \tcode{chunk_view::\exposid{iterator}} - template class @\exposid{iterator}@; // \expos +\rSec3[range.stride.view]{Class template \tcode{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: - chunk_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit chunk_view(V base, range_difference_t n); + 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{forward_range}@ { + 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}@) { - auto missing = (@\exposid{n_}@ - ranges::distance(@\exposid{base_}@) % @\exposid{n_}@) % @\exposid{n_}@; + 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_}@)); @@ -11448,9 +13674,9 @@ } } - 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_}@; + 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_}@)); @@ -11462,24 +13688,40 @@ constexpr auto size() requires @\libconcept{sized_range}@; constexpr auto size() const requires @\libconcept{sized_range}@; }; + + template + stride_view(R&&, range_difference_t) -> stride_view>; } \end{codeblock} +\indexlibraryctor{stride_view}% \begin{itemdecl} -constexpr explicit chunk_view(V base, range_difference_t n); +constexpr stride_view(V base, range_difference_t stride); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{n > 0} is \tcode{true}. +\tcode{stride > 0} is \tcode{true}. + +\pnum +\effects +Initializes \exposid{base_} with \tcode{std::move(base)} and +\exposid{stride_} with \tcode{stride}. +\end{itemdescr} +\indexlibrarymember{stride}{stride_view}% +\begin{itemdecl} +constexpr range_difference_t stride() const noexcept; +\end{itemdecl} + +\begin{itemdescr} \pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{n_} with \tcode{n}. +\returns +\exposid{stride_}. \end{itemdescr} +\indexlibrarymember{size}{stride_view}% \begin{itemdecl} constexpr auto size() requires @\libconcept{sized_range}@; constexpr auto size() const requires @\libconcept{sized_range}@; @@ -11490,78 +13732,84 @@ \effects Equivalent to: \begin{codeblock} -return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{n_}@)); +return @\exposid{to-unsigned-like}@(@\exposid{div-ceil}@(ranges::distance(@\exposid{base_}@), @\exposid{stride_}@)); \end{codeblock} \end{itemdescr} -\rSec3[range.chunk.fwd.iter]{Class template \tcode{chunk_view::\exposid{iterator}} for forward ranges} +\rSec3[range.stride.iterator]{Class template \tcode{stride_view::\exposid{iterator}}} -\indexlibraryglobal{chunk_view::iterator}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{view}@ V> - requires @\libconcept{forward_range}@ + template<@\libconcept{input_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 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{n_}@ = 0; // \expos - range_difference_t<@\exposid{Base}@> @\exposid{missing_}@ = 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{stride_}@ = 0; // \expos + range_difference_t<@\exposid{Base}@> @\exposid{missing_}@ = 0; // \expos - constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, // \expos + constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, // \expos range_difference_t<@\exposid{Base}@> missing = 0); - 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 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 - @\exposid{iterator}@() = default; - constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; + + constexpr @\exposid{iterator}@(@\exposid{iterator}@ other) requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; - constexpr iterator_t<@\exposid{Base}@> base() const; + constexpr iterator_t<@\exposid{Base}@> base() &&; + constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; + + constexpr decltype(auto) operator*() const { return *@\exposid{current_}@; } - constexpr value_type operator*() const; constexpr @\exposid{iterator}@& operator++(); - constexpr @\exposid{iterator}@ operator++(int); + 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 @\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 value_type operator[](difference_type n) const - 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, 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{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}@>; + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; - friend constexpr iterator operator+(const @\exposid{iterator}@& i, difference_type n) + friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; - friend constexpr iterator operator+(difference_type n, const @\exposid{iterator}@& i) + 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}@& i, difference_type n) + 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}@>>; @@ -11570,6 +13818,13 @@ 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} @@ -11584,9 +13839,30 @@ 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}. +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::iterator}% \begin{itemdecl} constexpr @\exposid{iterator}@(@\exposid{Parent}@* parent, iterator_t<@\exposid{Base}@> current, range_difference_t<@\exposid{Base}@> missing = 0); @@ -11595,12 +13871,13 @@ \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{current}, +Initializes \exposid{current_} with \tcode{std::move(current)}, \exposid{end_} with \tcode{ranges::end(parent->\exposid{base_})}, -\exposid{n_} with \tcode{parent\linebreak ->\exposid{n_}}, and +\exposid{stride_} with \tcode{parent->\exposid{stride_}}, and \exposid{missing_} with \tcode{missing}. \end{itemdescr} +\indexlibraryctor{stride_view::iterator}% \begin{itemdecl} constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>> @@ -11612,34 +13889,33 @@ \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{stride_} with \tcode{i.\exposid{stride_}}, and \exposid{missing_} with \tcode{i.\exposid{missing_}}. \end{itemdescr} +\indexlibrarymember{base}{stride_view::iterator}% \begin{itemdecl} -constexpr iterator_t<@\exposid{Base}@> base() const; +constexpr iterator_t<@\exposid{Base}@> base() &&; \end{itemdecl} \begin{itemdescr} \pnum \returns -\exposid{current_}. +\tcode{std::move(\exposid{current_})}. \end{itemdescr} +\indexlibrarymember{base}{stride_view::iterator}% \begin{itemdecl} -constexpr value_type operator*() const; +constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; \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_})}. +\exposid{current_}. \end{itemdescr} +\indexlibrarymember{operator++}{stride_view::iterator}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -11653,13 +13929,25 @@ \effects Equivalent to: \begin{codeblock} -@\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@, @\exposid{end_}@); +@\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{stride_}@, @\exposid{end_}@); return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator++}{stride_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{++*this;} +\end{itemdescr} + +\indexlibrarymember{operator++}{stride_view::iterator}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -11673,6 +13961,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{stride_view::iterator}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} @@ -11682,12 +13971,13 @@ \effects Equivalent to: \begin{codeblock} -ranges::advance(@\exposid{current_}@, @\exposid{missing_}@ - @\exposid{n_}@); +ranges::advance(@\exposid{current_}@, @\exposid{missing_}@ - @\exposid{stride_}@); @\exposid{missing_}@ = 0; return *this; \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator--}{stride_view::iterator}% \begin{itemdecl} constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} @@ -11703,35 +13993,36 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator+=}{stride_view::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator+=(difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} \pnum \expects -If \tcode{x} is positive, -\tcode{ranges::distance(\exposid{current_}, \exposid{end_}) > \exposid{n_} * (x - 1)} +If \tcode{n} is positive, +\tcode{ranges::distance(\exposid{current_}, \exposid{end_}) > \exposid{stride_} * (n - 1)} is \tcode{true}. \begin{note} -If \tcode{x} is negative, the \Fundescx{Effects} paragraph implies a precondition. +If \tcode{n} is negative, the \Fundescx{Effects} paragraph implies a precondition. \end{note} \pnum \effects Equivalent to: \begin{codeblock} -if (x > 0) { - @\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * x, @\exposid{end_}@); -} else if (x < 0) { - ranges::advance(@\exposid{current_}@, @\exposid{n_}@ * x + @\exposid{missing_}@); +if (n > 0) { + @\exposid{missing_}@ = ranges::advance(@\exposid{current_}@, @\exposid{stride_}@ * n, @\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::iterator}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator-=(difference_type x) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11740,22 +14031,24 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *this += -x}; +Equivalent to: \tcode{return *this += -x;} \end{itemdescr} +\indexlibrarymember{operator==}{stride_view::iterator}% \begin{itemdecl} -constexpr value_type operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{*(*this + n)}. +\tcode{x.\exposid{current_} == x.\exposid{end_}}. \end{itemdescr} +\indexlibrarymember{operator==}{stride_view::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{equality_comparable}@>; \end{itemdecl} \begin{itemdescr} @@ -11764,16 +14057,7 @@ \tcode{x.\exposid{current_} == y.\exposid{current_}}. \end{itemdescr} -\begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x.\exposid{current_} == x.\exposid{end_}}. -\end{itemdescr} - +\indexlibrarymember{operator<}{stride_view::iterator}% \begin{itemdecl} friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11785,6 +14069,7 @@ \tcode{x.\exposid{current_} < y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator>}{stride_view::iterator}% \begin{itemdecl} friend constexpr bool operator>(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11796,6 +14081,7 @@ Equivalent to: \tcode{return y < x;} \end{itemdescr} +\indexlibrarymember{operator<=}{stride_view::iterator}% \begin{itemdecl} friend constexpr bool operator<=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11807,6 +14093,7 @@ Equivalent to: \tcode{return !(y < x);} \end{itemdescr} +\indexlibrarymember{operator>=}{stride_view::iterator}% \begin{itemdecl} friend constexpr bool operator>=(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11818,10 +14105,10 @@ Equivalent to: \tcode{return !(x < y);} \end{itemdescr} +\indexlibrarymember{operator<=>}{stride_view::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}@>; + requires @\libconcept{random_access_range}@<@\exposid{Base}@> && @\libconcept{three_way_comparable}@>; \end{itemdecl} \begin{itemdescr} @@ -11830,6 +14117,7 @@ \tcode{x.\exposid{current_} <=> y.\exposid{current_}}. \end{itemdescr} +\indexlibrarymember{operator+}{stride_view::iterator}% \begin{itemdecl} friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11848,6 +14136,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-}{stride_view::iterator}% \begin{itemdecl} friend constexpr @\exposid{iterator}@ operator-(const @\exposid{iterator}@& i, difference_type n) requires @\libconcept{random_access_range}@<@\exposid{Base}@>; @@ -11864,6 +14153,7 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{operator-}{stride_view::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}@>>; @@ -11872,9 +14162,19 @@ \begin{itemdescr} \pnum \returns -\tcode{(x.\exposid{current_} - y.\exposid{current_} + x.\exposid{missing_} - y.\exposid{missing_}) / x.\exposid{n_}}. +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{operator-}{stride_view::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}@>>; @@ -11883,9 +14183,10 @@ \begin{itemdescr} \pnum \returns -\tcode{\exposid{div-ceil}(x.\exposid{end_} - x.\exposid{current_}, x.\exposid{n_})}. +\tcode{\exposid{div-ceil}(x.\exposid{end_} - x.\exposid{current_}, x.\exposid{stride_})}. \end{itemdescr} +\indexlibrarymember{operator-}{stride_view::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}@>>; @@ -11897,269 +14198,348 @@ Equivalent to: \tcode{return -(y - x);} \end{itemdescr} -\rSec2[range.slide]{Slide view} +\indexlibrarymember{iter_move}{stride_view::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} -\rSec3[range.slide.overview]{Overview} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} +\end{itemdescr} + +\indexlibrarymember{iter_swap}{stride_view::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 -\tcode{slide_view} takes a \libconcept{view} and a number \tcode{N} and -produces a \libconcept{view} -whose $\tcode{M}^\text{th}$ element is a \libconcept{view} over -the $\tcode{M}^\text{th}$ through -$(\tcode{M} + \tcode{N} - 1)^\text{th}$ elements -of the original \libconcept{view}. -If the original \libconcept{view} has fewer than \tcode{N} elements, -the resulting \libconcept{view} is empty. +\effects +Equivalent to: +\tcode{ranges::iter_swap(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 -\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: [1, 2] [2, 3] [3, 4] +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.slide.view]{Class template \tcode{slide_view}} +\rSec3[range.cartesian.view]{Class template \tcode{cartesian_product_view}} -\indexlibrarymember{begin}{slide_view}% -\indexlibrarymember{end}{slide_view}% -\indexlibrarymember{size}{slide_view}% \begin{codeblock} namespace std::ranges { - template - concept @\defexposconcept{slide-caches-nothing}@ = @\libconcept{random_access_range}@ && @\libconcept{sized_range}@; // \expos + 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{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_}@ = V(); // \expos - range_difference_t @\exposid{n_}@ = 0; // \expos - - // \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 + 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{ranges.cartesian.iterator}, class template \tcode{cartesian_product_view::\exposid{iterator}} + template class @\exposid{iterator}@; // \expos public: - slide_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit slide_view(V base, range_difference_t n); + constexpr cartesian_product_view() = default; + constexpr explicit cartesian_product_view(First first_base, Vs... bases); - constexpr auto begin() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); - constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; + constexpr @\exposid{iterator}@ begin() + requires (!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@); + constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{range}@ && ... && @\libconcept{range}@); - constexpr auto end() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); - constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; + 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; - constexpr auto size() requires @\libconcept{sized_range}@; - constexpr auto size() const requires @\libconcept{sized_range}@; + constexpr @\seebelow@ size() + requires @\exposconcept{cartesian-product-is-sized}@; + constexpr @\seebelow@ size() const + requires @\exposconcept{cartesian-product-is-sized}@; }; - template - slide_view(R&& r, range_difference_t) -> slide_view>; + template + cartesian_product_view(Vs&&...) -> cartesian_product_view...>; } \end{codeblock} \begin{itemdecl} -constexpr explicit slide_view(V base, range_difference_t n); +constexpr explicit cartesian_product_view(First first_base, Vs... bases); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{n_} with \tcode{n}. +Initializes \exposid{bases_} +with \tcode{std::move(first_base), std::move(bases)...}. \end{itemdescr} \begin{itemdecl} -constexpr auto begin() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); +constexpr @\exposid{iterator}@ begin() + requires (!@\exposconcept{simple-view}@ || ... || !@\exposconcept{simple-view}@); \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}. + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return \exposid{iterator}(\exposid{tuple-transform}(ranges::begin, \exposid{bases_}));} \end{itemdescr} \begin{itemdecl} -constexpr auto begin() const requires @\exposconcept{slide-caches-nothing}@; +constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{range}@ && ... && @\libconcept{range}@); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{\exposid{iterator}(ranges::begin(\exposid{base_}), \exposid{n_})}. +\effects +Equivalent to: +\tcode{return \exposid{iterator}(\exposid{tuple-transform}(ranges::begin, \exposid{bases_}));} \end{itemdescr} \begin{itemdecl} -constexpr auto end() - requires (!(@\exposconcept{simple-view}@ && @\exposconcept{slide-caches-nothing}@)); +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} \pnum -\returns +Let: \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} +\exposid{is-const} be \tcode{true} for the const-qualified overload, and +\tcode{false} otherwise; \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} +\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 -Otherwise, \tcode{\exposid{sentinel}(ranges::end(\exposid{base_}))}. +\tcode{\exposid{begin-or-first-end}(rng)} be expression-equivalent to +\tcode{\exposid{is-empty} ? ranges::begin(rng) : \exposid{cartesian-common-arg-end}(rng)} +if \tcode{rng} is the first underlying range and +\tcode{ranges::begin(rng)} otherwise. \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}. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{iterator}@<@\exposid{is-const}@> it(@\exposid{tuple-transform}@( + [](auto& rng){ return @\exposid{begin-or-first-end}@(rng); }, @\exposid{bases_}@)); +return it; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr auto end() const requires @\exposconcept{slide-caches-nothing}@; +constexpr default_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{begin() + range_difference_t(size())}. +\tcode{default_sentinel}. \end{itemdescr} \begin{itemdecl} -constexpr auto size() requires @\libconcept{sized_range}@; -constexpr auto size() const requires @\libconcept{sized_range}@; +constexpr @\seebelow@ size() + requires @\exposconcept{cartesian-product-is-sized}@; +constexpr @\seebelow@ size() const + requires @\exposconcept{cartesian-product-is-sized}@; \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} +The return type is an \impldef{return type of \tcode{cartesian_product_view::size}} unsigned-integer-like type. + +\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. + +\pnum +Let $p$ be the product of the sizes of all the ranges in \exposid{bases_}. + +\pnum +\expects +$p$ can be represented by the return type. + +\pnum +\returns +$p$. \end{itemdescr} -\rSec3[range.slide.iterator]{Class template \tcode{slide_view::\exposid{iterator}}} +\rSec3[ranges.cartesian.iterator]{Class template \tcode{cartesian_product_view::\exposid{iterator}}} -\indexlibraryglobal{slide_view::iterator}% \begin{codeblock} namespace std::ranges { - template<@\libconcept{forward_range}@ V> - requires @\libconcept{view}@ + template<@\libconcept{input_range}@ First, @\libconcept{forward_range}@... Vs> + requires (@\libconcept{view}@ && ... && @\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 \tcode{\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}@>); - - 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}@>; - + class cartesian_product_view::@\exposid{iterator}@ { public: 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}@>; + 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<@\exposid{Base}@>>; + @\exposid{iterator}@() requires @\libconcept{forward_range}@<@\exposid{maybe-const}@> = 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 @\exposid{iterator}@ operator++(int); + constexpr void operator++(int); + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{maybe-const}@>; - 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--() + 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 @\libconcept{random_access_range}@<@\exposid{Base}@>; + requires @\exposconcept{cartesian-product-is-random-access}@; constexpr @\exposid{iterator}@& operator-=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + requires @\exposconcept{cartesian-product-is-random-access}@; - constexpr auto operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; + 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); + 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 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}@>; + requires @\exposconcept{all-random-access}@; - 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 @\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 @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; + requires @\exposconcept{cartesian-is-sized-sentinel}@; + + friend constexpr difference_type operator-(@\exposid{iterator}@ i, default_sentinel_t) + requires @\exposconcept{cartesian-is-sized-sentinel}@; + friend constexpr difference_type operator-(default_sentinel_t, @\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: + @\exposid{maybe-const}@* @\exposid{parent_}@ = nullptr; // \expos + tuple>, + iterator_t<@\exposid{maybe-const}@>...> @\exposid{current_}@; // \expos + + template + constexpr void @\exposid{next}@(); // \expos + + template + constexpr void @\exposid{prev}@(); // \expos + + template + constexpr difference_type @\exposid{distance-from}@(Tuple t); // \expos + + constexpr explicit @\exposid{iterator}@(tuple>, + iterator_t<@\exposid{maybe-const}@>...> current); // \expos }; } \end{codeblock} @@ -12168,60 +14548,130 @@ \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}. +If \tcode{\exposconcept{cartesian-product-is-random-access}} +is modeled, +then \tcode{iterator_con\-cept} denotes \tcode{random_access_iterator_tag}. \item -Otherwise, if \exposid{Base} models \libconcept{bidirectional_range}, -then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. +Otherwise, +if \tcode{\exposconcept{cartesian-product-is-bidirectional}} +is modeled, +then \tcode{it\-erator_concept} denotes \tcode{bidirectional_iterator_tag}. \item -Otherwise, \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. +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} \pnum -If the invocation of any non-const member function of \exposid{iterator} -exits via an exception, the \exposid{iterator} acquires a singular value. +\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. +\pnum \begin{itemdecl} -constexpr @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current, range_difference_t<@\exposid{Base}@> n) - requires (!@\exposconcept{slide-caches-first}@<@\exposid{Base}@>); +template + constexpr void @\exposid{next}@(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{current_} with \tcode{current} and -\exposid{n_} with \tcode{n}. +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}@(); + } +} +\end{codeblock} \end{itemdescr} \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}@>; +template + constexpr void @\exposid{prev}@(); \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}. +Equivalent to: +\begin{codeblock} +auto& it = std::get(@\exposid{current_}@); +if (it == ranges::begin(std::get(@\exposid{parent_}@->@\exposid{bases_}@))) { + it = @\exposid{cartesian-common-arg-end}@(std::get(@\exposid{parent_}@->@\exposid{bases_}@)); + if constexpr (N > 0) { + @\exposid{prev}@(); + } +} +--it; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) - requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +template + constexpr difference_type @\exposid{distance-from}@(Tuple t); +\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 < \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} + +\pnum +\expects +\exposid{scaled-sum} can be represented by \tcode{difference_type}. + +\pnum +\returns +\exposid{scaled-sum}. +\end{itemdescr} + +\begin{itemdecl} +constexpr explicit @\exposid{iterator}@(tuple>, + iterator_t<@\exposid{maybe-const}@>...> current); \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} +Initializes \exposid{current_} with \tcode{std::move(current)}. +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && + (@\libconcept{convertible_to}@, iterator_t> && + ... && @\libconcept{convertible_to}@, iterator_t>); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. \end{itemdescr} \begin{itemdecl} @@ -12230,8 +14680,11 @@ \begin{itemdescr} \pnum -\returns -\tcode{views::counted(\exposid{current_}, \exposid{n_})}. +\effects +Equivalent to: +\begin{codeblock} +return @\exposid{tuple-transform}@([](auto& i) -> decltype(auto) { return *i; }, @\exposid{current_}@); +\end{codeblock} \end{itemdescr} \begin{itemdecl} @@ -12240,22 +14693,57 @@ \begin{itemdescr} \pnum -\expects -\exposid{current_} and \exposid{last_ele_} (if present) are incrementable. +\effects +Equivalent to: +\begin{codeblock} +@\exposid{next}@(); +return *this; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} +\begin{itemdescr} \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. +\effects +Equivalent to \tcode{++*this}. +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{maybe-const}@>; +\end{itemdecl} +\begin{itemdescr} \pnum -\returns -\tcode{*this}. +\effects +Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr @\exposid{iterator}@& operator--() + requires @\exposconcept{cartesian-product-is-bidirectional}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{prev}@(); +return *this; +\end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +constexpr @\exposid{iterator}@ operator--(int) + requires @\exposconcept{cartesian-product-is-bidirectional}@; \end{itemdecl} \begin{itemdescr} @@ -12264,33 +14752,54 @@ Equivalent to: \begin{codeblock} auto tmp = *this; -++*this; +--*this; return tmp; \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator+=(difference_type x) + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{orig} be the value of \tcode{*this} before the call. + +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} + \pnum \expects -\exposid{current_} and \exposid{last_ele_} (if present) are decrementable. +\tcode{x} is in the range +$[\tcode{ranges::distance(*this, ranges::begin(*\exposid{parent_}))},$\newline +$\tcode{ranges::distance(*this, ranges::end(*\exposid{parent_}))}]$. \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. +\effects +Sets the value of \tcode{*this} to \tcode{ret}. \pnum \returns \tcode{*this}. + +\pnum +\complexity +Constant. \end{itemdescr} \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; +constexpr @\exposid{iterator}@& operator-=(difference_type x) + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} @@ -12298,373 +14807,604 @@ \effects Equivalent to: \begin{codeblock} -auto tmp = *this; ---*this; -return tmp; +*this += -x; +return *this; \end{codeblock} \end{itemdescr} \begin{itemdecl} -constexpr iterator& operator+=(difference_type x) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +constexpr reference operator[](difference_type n) const + requires @\exposconcept{cartesian-product-is-random-access}@; \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}. +\effects +Equivalent to: \tcode{return *((*this) + n);} \end{itemdescr} \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) + requires @\libconcept{equality_comparable}@>>; \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. +\effects +Equivalent to: \tcode{return x.\exposid{current_} == y.\exposid{current_};} +\end{itemdescr} -\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{itemdecl} +friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +\end{itemdecl} +\begin{itemdescr} \pnum \returns -\tcode{*this}. +\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} -constexpr auto operator[](difference_type n) const - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +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 views::counted(\exposid{current_} + n, \exposid{n_});} +Equivalent to: \tcode{return x.\exposid{current_} <=> y.\exposid{current_};} \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +friend constexpr @\exposid{iterator}@ operator+(const @\exposid{iterator}@& x, difference_type y) + requires @\exposconcept{cartesian-product-is-random-access}@; \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_}}. +\effects +Equivalent to: \tcode{return \exposid{iterator}(x) += y;} \end{itemdescr} \begin{itemdecl} -friend constexpr bool operator<(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{random_access_range}@<@\exposid{Base}@>; +friend constexpr @\exposid{iterator}@ operator+(difference_type x, const @\exposid{iterator}@& y) + requires @\exposconcept{cartesian-product-is-random-access}@; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} < y.\exposid{current_}}. +\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}@>; +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 y < x;} +Equivalent to: \tcode{return \exposid{iterator}(x) -= y;} \end{itemdescr} \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-(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) + requires @\exposconcept{cartesian-is-sized-sentinel}@; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !(y < x);} +Equivalent to: \tcode{return x.\exposid{distance-from}(y.\exposid{current_});} \end{itemdescr} \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-(@\exposid{iterator}@ i, default_sentinel_t) + requires @\exposconcept{cartesian-is-sized-sentinel}@; \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 !(x < y);} +Equivalent to: \tcode{return i.\exposid{distance-from}(\exposid{end-tuple});} \end{itemdescr} \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}@>; +friend constexpr difference_type operator-(default_sentinel_t s, @\exposid{iterator}@ i) + requires @\exposconcept{cartesian-is-sized-sentinel}@; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} <=> y.\exposid{current_}}. +\effects +Equivalent to: \tcode{return -(i - s);} \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 auto iter_move(const @\exposid{iterator}@& i) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -auto r = i; -r += n; -return r; -\end{codeblock} +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} \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 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 \effects -Equivalent to: +For every integer $0 \le i \le \tcode{sizeof...(Vs)}$, performs: \begin{codeblock} -auto r = i; -r -= n; -return r; +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} \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} +\rSec1[coro.generator]{Range generators} + +\rSec2[coroutine.generator.overview]{Overview} -\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} +Class template \tcode{generator} presents +a \libconcept{view} of the elements yielded by the evaluation of a coroutine. -\rSec3[range.slide.sentinel]{Class \tcode{slide_view::\exposid{sentinel}}} +\pnum +A \tcode{generator} generates a sequence of elements by +repeatedly resuming the coroutine from which it was returned. +Elements of the sequence are produced by the coroutine +each time a \tcode{co_yield} statement is evaluated. +When the \tcode{co_yield} statement is of the form +\tcode{co_yield elements_of(r)}, +each element of the range \tcode{r} +is successively produced as an element of the sequence. +\begin{example} +\begin{codeblock} +generator ints(int start = 0) { + while (true) + co_yield start++; +} -\indexlibraryglobal{chunk_view::sentinel}% +void f() { + for (auto i : ints() | views::take(3)) + cout << i << ' '; // prints \tcode{0 1 2} +} +\end{codeblock} +\end{example} + +\rSec2[generator.syn]{Header \tcode{} synopsis} + +\indexheader{generator}% \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 +namespace std { + // \ref{coro.generator.class}, class template \tcode{generator} + template + class generator; +} +\end{codeblock} + +\rSec2[coro.generator.class]{Class template \tcode{generator}} + +\begin{codeblock} +namespace std { + 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 + + // \ref{coro.generator.iterator}, class \tcode{generator::\exposid{iterator}} + class @\exposidnc{iterator}@; // \expos public: - @\exposid{sentinel}@() = default; + using yielded = + conditional_t, @\exposid{reference}@, const @\exposid{reference}@&>; - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + // \ref{coro.generator.promise}, class \tcode{generator::promise_type} + class promise_type; - friend constexpr range_difference_t - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; + generator(const generator&) = delete; + generator(generator&& other) noexcept; - friend constexpr range_difference_t - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; + ~generator(); + + generator& operator=(generator other) noexcept; + + @\exposid{iterator}@ begin(); + default_sentinel_t end() const noexcept; + + private: + coroutine_handle @\exposid{coroutine_}@ = nullptr; // \expos + unique_ptr>> @\exposid{active_}@; // \expos }; } \end{codeblock} +\pnum +\mandates +\begin{itemize} +\item +If \tcode{Allocator} is not \tcode{void}, +\tcode{allocator_traits::pointer} is a pointer type. +\item +\exposid{value} is a cv-unqualified object type. +\item +\exposid{reference} is either a reference type, or +a cv-unqualified object type that models \libconcept{copy_constructible}. +\item +Let \tcode{RRef} denote \tcode{remove_reference_t<\exposid{reference}>\&\&} +if \exposid{reference} is a reference type, +and \exposid{reference} otherwise. +Each of: +\begin{itemize} +\item \tcode{\libconcept{common_reference_with}<\exposid{reference}\&\&, \exposid{value}\&>}, +\item \tcode{\libconcept{common_reference_with}<\exposid{reference}\&\&, RRef\&\&>}, and +\item \tcode{\libconcept{common_reference_with}} +\end{itemize} +is modeled. +\begin{note} +These requirements ensure the exposition-only \exposid{iterator} type +can model \libconcept{indirectly_readable} and thus \libconcept{input_iterator}. +\end{note} +\end{itemize} + +\pnum +If \tcode{Allocator} is not \tcode{void}, +it shall meet the \oldconcept{Allocator} requirements. + +\pnum +Specializations of \tcode{generator} model +\libconcept{view} and \libconcept{input_range}. + +\pnum +The behavior of a program that adds a specialization +for \tcode{generator} is undefined. + +\rSec2[coro.generator.members]{Members} + +\indexlibraryctor{generator}% +\begin{itemdecl} +generator(generator&& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{coroutine_} with +\tcode{exchange(other.\exposid{coroutine_}, \{\})} and +\exposid{active_} with +\tcode{exchange(\brk{}other.active_, nullptr)}. + \pnum \begin{note} -\exposid{sentinel} is used -only when \tcode{\exposconcept{slide-caches-first}} is \tcode{true}. +Iterators previously obtained from \tcode{other} are not invalidated; +they become iterators into \tcode{*this}. \end{note} +\end{itemdescr} +\indexlibrarydtor{generator}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(sentinel_t end); +~generator(); \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{end_} with \tcode{end}. +Equivalent to: +\begin{codeblock} +if (@\exposid{coroutine_}@) { + @\exposid{coroutine_}@.destroy(); +} +\end{codeblock} + +\pnum +\begin{note} +Ownership of recursively yielded generators +is held in awaitable objects +in the coroutine frame of the yielding generator, +so destroying the root generator +effectively destroys the entire stack of yielded generators. +\end{note} \end{itemdescr} +\indexlibrarymember{operator=}{generator}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +generator& operator=(generator other) noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +swap(@\exposid{coroutine_}@, other.@\exposid{coroutine_}@); +swap(@\exposid{active_}@, other.@\exposid{active_}@); +\end{codeblock} + \pnum \returns -\tcode{x.\exposid{last_ele_} == y.\exposid{end_}}. +\tcode{*this}. + +\pnum +\begin{note} +Iterators previously obtained from \tcode{other} are not invalidated; +they become iterators into \tcode{*this}. +\end{note} \end{itemdescr} +\indexlibrarymember{begin}{generator}% \begin{itemdecl} -friend constexpr range_difference_t - operator-(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +@\exposid{iterator}@ begin(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\exposid{coroutine_} refers to a coroutine +suspended at its initial suspend point\iref{dcl.fct.def.coroutine}. + +\pnum +\effects +Pushes \exposid{coroutine_} into \tcode{*\exposid{active_}}, +then evaluates \tcode{\exposid{coroutine_}.resume()}. + \pnum \returns -\tcode{x.\exposid{last_ele_} - y.\exposid{end_}}. +An \exposid{iterator} object +whose member \exposid{coroutine_} +refers to the same coroutine as does +\exposid{coroutine_}. + +\pnum +\begin{note} +A program that calls \tcode{begin} more than once on the same generator +has undefined behavior. +\end{note} \end{itemdescr} +\indexlibrarymember{end}{generator}% \begin{itemdecl} -friend constexpr range_difference_t - operator-(const @\exposid{sentinel}@& y, const @\exposid{iterator}@& x) - requires @\libconcept{sized_sentinel_for}@, iterator_t>; +default_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{y.\exposid{end_} - x.\exposid{last_ele_}}. +\tcode{default_sentinel}. \end{itemdescr} -\rSec2[range.chunk.by]{Chunk by view} +\rSec2[coro.generator.promise]{Class \tcode{generator::promise_type}} -\rSec3[range.chunk.by.overview]{Overview} +\begin{codeblock} +namespace std { + template + class generator::promise_type { + public: + generator get_return_object() noexcept; -\pnum -\tcode{chunk_by_view} takes a \libconcept{view} and a predicate, and -splits the \libconcept{view} into \tcode{subrange}s -between each pair of adjacent elements -for which the predicate returns \tcode{false}. + suspend_always initial_suspend() const noexcept { return {}; } + auto final_suspend() noexcept; -\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}; + suspend_always yield_value(yielded val) noexcept; -for (auto r : v | views::chunk_by(ranges::less_equal{})) { - cout << '['; - auto sep = ""; - for(auto i : r) { - cout << sep << i; - sep = ", "; - } - cout << "] "; -} -\end{codeblock} -The above prints: \tcode{[1, 2, 2, 3] [0, 4, 5] [2]} -\end{example} + auto yield_value(const remove_reference_t& lval) + requires is_rvalue_reference_v && + @\libconcept{constructible_from}@, const remove_reference_t&>; -\rSec3[range.chunk.by.view]{Class template \tcode{chunk_by_view}} + template + requires @\libconcept{same_as}@::yielded, yielded> + auto yield_value(ranges::elements_of&&, Unused> g) noexcept; -\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 - @\exposid{copyable-box}@ @\exposid{pred_}@ = Pred(); // \expos + template + requires @\libconcept{convertible_to}@, yielded> + auto yield_value(ranges::elements_of r) noexcept; - // \ref{range.chunk.by.iter}, class \tcode{chunk_by_view::\exposid{iterator}} - class @\exposid{iterator}@; // \expos + void await_transform() = delete; - public: - chunk_by_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; - constexpr explicit chunk_by_view(V base, Pred pred); + void return_void() const noexcept {} + void unhandled_exception(); - constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } - constexpr V base() && { return std::move(@\exposid{base_}@); } + void* operator new(size_t size) + requires @\libconcept{same_as}@ || @\libconcept{default_initializable}@; - constexpr const Pred& pred() const; + template + requires @\libconcept{same_as}@ || @\libconcept{convertible_to}@ + void* operator new(size_t size, allocator_arg_t, const Alloc& alloc, const Args&...); - constexpr @\exposid{iterator}@ begin(); - constexpr auto end(); + template + requires @\libconcept{same_as}@ || @\libconcept{convertible_to}@ + void* operator new(size_t size, const This&, allocator_arg_t, const Alloc& alloc, + const Args&...); - constexpr iterator_t @\exposid{find-next}@(iterator_t); // \expos - constexpr iterator_t @\exposid{find-prev}@(iterator_t) // \expos - requires @\libconcept{bidirectional_range}@; - }; + void operator delete(void* pointer, size_t size) noexcept; - template - chunk_by_view(R&&, Pred) -> chunk_by_view, Pred>; + private: + add_pointer_t @\exposid{value_}@ = nullptr; // \expos + exception_ptr @\exposid{except_}@; // \expos + }; } \end{codeblock} +\indexlibrarymember{get_return_object}{generator::promise_type}% \begin{itemdecl} -constexpr explicit chunk_by_view(V base, Pred pred); +generator get_return_object() noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \exposid{base_} with \tcode{std::move(base)} and -\exposid{pred_} with \tcode{std::move(pred)}. +\returns +A \tcode{generator} object whose member \exposid{coroutine_} +is \tcode{coroutine_handle::\brk{}from_promise(*this)}, +and whose member \exposid{active_} points to an empty stack. \end{itemdescr} -\indexlibrarymember{pred}{chunk_by_view}% +\indexlibrarymember{final_suspend}{generator::promise_type}% \begin{itemdecl} -constexpr const Pred& pred() const; +auto final_suspend() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +A handle referring to the coroutine +whose promise object is \tcode{*this} +is at the top of \tcode{*\exposid{active_}} +of some \tcode{generator} object \tcode{x}. +This function is called by that coroutine +upon reaching its final suspend point\iref{dcl.fct.def.coroutine}. + +\pnum +\returns +An awaitable object of unspecified type\iref{expr.await} +whose member functions arrange for the +calling coroutine to be suspended, +pop the coroutine handle +from the top of \tcode{*x.\exposid{active_}}, +and resume execution of the coroutine referred to by +\tcode{x.\exposid{active_}->top()} +if \tcode{*x.\exposid{active_}} is not empty. +If it is empty, control flow returns to the +current coroutine caller or resumer\iref{dcl.fct.def.coroutine}. +\end{itemdescr} + +\indexlibrarymember{yield_value}{generator::promise_type}% +\begin{itemdecl} +suspend_always yield_value(yielded val) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return *\exposid{pred_};} +Equivalent to \tcode{\exposid{value_} = addressof(val)}. + +\pnum +\returns +\tcode{\{\}}. \end{itemdescr} +\indexlibrarymember{yield_value}{generator::promise_type}% \begin{itemdecl} -constexpr @\exposid{iterator}@ begin(); +auto yield_value(const remove_reference_t& lval) + requires is_rvalue_reference_v && + @\libconcept{constructible_from}@, const remove_reference_t&>; \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{\exposid{pred_}.has_value()} is \tcode{true}. +A handle referring to the coroutine +whose promise object is \tcode{*this} +is at the top of \tcode{*\exposid{active_}} +of some \tcode{generator} object \tcode{x}. \pnum \returns -\tcode{\exposid{iterator}(*this, ranges::begin(\exposid{base_}), \exposid{find-next}(ranges::begin(\exposid{base_})))}. +An awaitable object of an unspecified type\iref{expr.await} +that stores an object of type \tcode{remove_cvref_t} +direct-non-list-initialized with \tcode{lval}, +whose member functions arrange for +\exposid{value_} to point to that stored object +and then suspend the coroutine. + +\pnum +\throws +Any exception thrown by the initialization of the stored object. \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. +A \grammarterm{yield-expression} that calls this function +has type \tcode{void}\iref{expr.yield}. \end{itemdescr} +\indexlibrarymember{yield_value}{generator::promise_type}% \begin{itemdecl} -constexpr auto end(); +template + requires @\libconcept{same_as}@::yielded, yielded> + auto yield_value(ranges::elements_of&&, Unused> g) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +A handle referring to the coroutine +whose promise object is \tcode{*this} +is at the top of \tcode{*\exposid{active_}} +of some \tcode{generator} object \tcode{x}. +The coroutine referred to by +\tcode{g.range.\exposid{coroutine_}} +is suspended at its initial suspend point. + +\pnum +\returns +An awaitable object of an unspecified type\iref{expr.await} +into which \tcode{g.range} is moved, +whose member \tcode{await_ready} returns \tcode{false}, +whose member \tcode{await_suspend} +% FIXME: The mbox prevents TeX from adding a bizarre hyphen after coroutine_. +pushes \tcode{g.range.}\mbox{\exposid{coroutine_}} +into \tcode{*x.\exposid{active_}} +and resumes execution of the coroutine referred to +by \tcode{g.range.\brk{}\exposid{coroutine_}}, and +whose member \tcode{await_resume} evaluates +\tcode{rethrow_exception(\exposid{except_})} +if \tcode{bool(\exposid{ex\-cept_})} is \tcode{true}. +If \tcode{bool(\exposid{except_})} is \tcode{false}, +the \tcode{await_resume} member has no effects. + +\pnum +\remarks +A \grammarterm{yield-expression} that calls this function +has type \tcode{void}\iref{expr.yield}. +\end{itemdescr} + +\indexlibrarymember{yield_value}{generator::promise_type}% +\begin{itemdecl} +template + requires @\libconcept{convertible_to}@, yielded> + auto yield_value(ranges::elements_of r) noexcept; \end{itemdecl} \begin{itemdescr} @@ -12672,210 +15412,222 @@ \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; -} +auto nested = [](allocator_arg_t, Alloc, ranges::iterator_t i, ranges::sentinel_t s) + -> generator, Alloc> { + for (; i != s; ++i) { + co_yield static_cast(*i); + } + }; +return yield_value(ranges::elements_of(nested( + allocator_arg, r.allocator, ranges::begin(r.range), ranges::end(r.range)))); \end{codeblock} + +\pnum +\remarks +A \grammarterm{yield-expression} that calls this function +has type \tcode{void}\iref{expr.yield}. \end{itemdescr} +\indexlibrarymember{unhandled_exception}{generator::promise_type}% \begin{itemdecl} -constexpr iterator_t @\exposid{find-next}@(iterator_t current); +void unhandled_exception(); \end{itemdecl} \begin{itemdescr} \pnum \expects -\tcode{\exposid{pred_}.has_value()} is \tcode{true}. +A handle referring to the coroutine whose promise object is \tcode{*this} +is at the top of \tcode{*\exposid{active_}} +of some \tcode{generator} object \tcode{x}. \pnum -\returns -\begin{codeblock} -ranges::next(ranges::adjacent_find(current, ranges::end(@\exposid{base_}@), not_fn(ref(*@\exposid{pred_}@))), - 1, ranges::end(@\exposid{base_}@)) -\end{codeblock} +\effects +If the handle referring to the coroutine +whose promise object is \tcode{*this} +is the sole element of \tcode{*x.\exposid{active_}}, +equivalent to: \tcode{throw;} +Otherwise, assigns \tcode{current_exception()} to \exposid{except_}. \end{itemdescr} +\indexlibrarymember{operator new}{generator::promise_type}% \begin{itemdecl} -constexpr iterator_t @\exposid{find-prev}@(iterator_t current) requires @\libconcept{bidirectional_range}@; +void* operator new(size_t size) + 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} \begin{itemdescr} \pnum -\expects +Let \tcode{A} be \begin{itemize} \item -\tcode{current} is not equal to \tcode{ranges::begin(\exposid{base_})}. +\tcode{Allocator}, if it is not \tcode{void}, \item -\tcode{\exposid{pred_}.has_value()} is \tcode{true}. +\tcode{Alloc} for the overloads with a template parameter \tcode{Alloc}, or +\item +\tcode{allocator} otherwise. \end{itemize} +Let \tcode{B} be \tcode{allocator_traits::template rebind_alloc} +where \tcode{U} is an unspecified type whose size and alignment +are both \mname{STDCPP_DEFAULT_NEW_ALIGNMENT}. + +\pnum +\mandates +\tcode{allocator_traits::pointer} is a pointer type. + +\pnum +\effects +Initializes an allocator \tcode{b} of type \tcode{B} with \tcode{A(alloc)}, +for the overloads with a function parameter \tcode{alloc}, +and with \tcode{A()} otherwise. +Uses \tcode{b} to allocate storage for the smallest array +of \tcode{U} sufficient to provide storage for +a coroutine state of size \tcode{size}, and +unspecified additional state necessary to ensure that +\tcode{operator delete} can later deallocate this memory block +with an allocator equal to \tcode{b}. \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} +A pointer to the allocated storage. \end{itemdescr} -\rSec3[range.chunk.by.iter]{Class \tcode{chunk_by_view::\exposid{iterator}}} +\indexlibrarymember{operator delete}{generator::promise_type}% +\begin{itemdecl} +void operator delete(void* pointer, size_t size) noexcept; +\end{itemdecl} -\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 +\begin{itemdescr} +\pnum +\expects +\tcode{pointer} was returned from an invocation of +one of the above overloads of \tcode{operator new} +with a \tcode{size} argument equal to \tcode{size}. - constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, // \expos - iterator_t next); +\pnum +\effects +Deallocates the storage pointed to by \tcode{pointer} +using an allocator equivalent to that used to allocate it. +\end{itemdescr} +\rSec2[coro.generator.iterator]{Class \tcode{generator::\exposid{iterator}}} + +\begin{codeblock} +namespace std { + template + class generator::@\exposid{iterator}@ { public: - using value_type = subrange>; - using difference_type = range_difference_t; - using iterator_category = input_iterator_tag; - using iterator_concept = @\seebelow@; + using value_type = @\exposid{value}@; + using difference_type = ptrdiff_t; - @\exposid{iterator}@() = default; + @\exposid{iterator}@(@\exposid{iterator}@&& other) noexcept; + @\exposid{iterator}@& operator=(@\exposid{iterator}@&& other) noexcept; - constexpr value_type operator*() const; - constexpr @\exposid{iterator}@& operator++(); - constexpr @\exposid{iterator}@ operator++(int); + @\exposid{reference}@ operator*() const noexcept(is_nothrow_copy_constructible_v<@\exposid{reference}@>); + @\exposid{iterator}@& operator++(); + void operator++(int); - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; + friend bool operator==(@\exposid{iterator}@ i, default_sentinel_t); - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); - friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); + private: + coroutine_handle @\exposid{coroutine_}@; // \expos }; } \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} - +\indexlibraryctor{generator::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@(chunk_by_view& parent, iterator_t current, iterator_t next); +@\exposid{iterator}@(@\exposid{iterator}@&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Initializes \exposid{parent_} with \tcode{addressof(parent)}, -\exposid{current_} with \tcode{current}, and -\exposid{next_} with \tcode{next}. +Initializes \exposid{coroutine_} +with \tcode{exchange(other.\exposid{coroutine_}, \{\})}. \end{itemdescr} +\indexlibrarymember{operator=}{generator::iterator}% \begin{itemdecl} -constexpr value_type operator*() const; +@\exposid{iterator}@& operator=(@\exposid{iterator}@&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\exposid{current_} is not equal to \exposid{next_}. +\effects +Equivalent to +\tcode{\exposid{coroutine_} = exchange(other.\exposid{coroutine_}, \{\})}. \pnum \returns -\tcode{subrange(\exposid{current_}, \exposid{next_})}. +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator*}{generator::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator++(); +@\exposid{reference}@ operator*() const noexcept(is_nothrow_copy_constructible_v<@\exposid{reference}@>); \end{itemdecl} \begin{itemdescr} \pnum \expects -\exposid{current_} is not equal to \exposid{next_}. +For some \tcode{generator} object \tcode{x}, +\exposid{coroutine_} is in \tcode{*x.\exposid{active_}} and +\tcode{x.\exposid{active_}->top()} refers to +a suspended coroutine with promise object \tcode{p}. \pnum \effects Equivalent to: -\begin{codeblock} -@\exposid{current_}@ = @\exposid{next_}@; -@\exposid{next_}@ = @\exposid{parent_}@->@\exposid{find-next}@(@\exposid{current_}@); -return *this; -\end{codeblock} +\tcode{return static_cast<\exposid{reference}>(*p.\exposid{value_});} \end{itemdescr} +\indexlibrarymember{operator++}{generator::iterator}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int); +@\exposid{iterator}@& operator++(); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; -++*this; -return tmp; -\end{codeblock} -\end{itemdescr} - -\begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; -\end{itemdecl} +\expects +For some \tcode{generator} object \tcode{x}, +\exposid{coroutine_} is in \tcode{*x.\exposid{active_}}. -\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} -\end{itemdescr} +Equivalent to \tcode{x.\exposid{active_}->top().resume()}. -\begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; -\end{itemdecl} - -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -auto tmp = *this; ---*this; -return tmp; -\end{codeblock} +\returns +\tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator++}{generator::iterator}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y); +void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} == y.\exposid{current_}}. +\effects +Equivalent to \tcode{++*this}. \end{itemdescr} +\indexlibrarymember{operator==}{generator::iterator}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); +friend bool operator==(@\exposid{iterator}@ i, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{x.\exposid{current_} == x.\exposid{next_}}. +\effects +Equivalent to: \tcode{return i.\exposid{coroutine_}.done();} \end{itemdescr} diff --git a/source/regex.tex b/source/regex.tex index 5ee8aa28ed..1503118992 100644 --- a/source/regex.tex +++ b/source/regex.tex @@ -264,7 +264,7 @@ 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; +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 @@ -2691,8 +2691,8 @@ \begin{itemdescr} \pnum \expects -\tcode{BidirectionalIterator} meets the -\oldconcept{BidirectionalIterator} requirements\iref{bidirectional.iterators}. +\tcode{BidirectionalIterator} models +\libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. \pnum \effects @@ -2881,8 +2881,8 @@ \begin{itemdescr} \pnum \expects -\tcode{BidirectionalIterator} meets the -\oldconcept{BidirectionalIterator} requirements\iref{bidirectional.iterators}. +\tcode{BidirectionalIterator} models +\libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. \pnum \effects @@ -3228,6 +3228,7 @@ 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++(); @@ -3533,6 +3534,7 @@ 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++(); @@ -3848,7 +3850,7 @@ \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 +to \tcode{traits_inst.lookup_classname} can be bitwise \logop{or}'ed together and subsequently passed to \tcode{traits_inst.isctype}. \pnum diff --git a/source/statements.tex b/source/statements.tex index 65b4534ee1..bca992c936 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -46,7 +46,7 @@ \item for a \grammarterm{compound-statement}, any \grammarterm{statement} of its \grammarterm{statement-seq}, \item - for a \grammarterm{selection-statement}, any of its \grammarterm{statement}{s} (but not its \grammarterm{init-statement}), or + for a \grammarterm{selection-statement}, any of its \grammarterm{statement}{s} or \grammarterm{compound-statement}{s} (but not its \grammarterm{init-statement}), or \item for an \grammarterm{iteration-statement}, its \grammarterm{statement} (but not an \grammarterm{init-statement}). \end{itemize} @@ -117,19 +117,25 @@ \grammarterm{decl-specifier} shall be either a \grammarterm{type-specifier} or \keyword{constexpr}. -\rSec1[stmt.label]{Labeled statement}% +\rSec1[stmt.label]{Label}% \indextext{statement!labeled} \pnum \indextext{statement!labeled}% \indextext{\idxcode{:}!label specifier}% -A statement can be labeled. +A label can be added to a statement or +used anywhere in a \grammarterm{compound-statement}. + +\begin{bnf} +\nontermdef{label}\br + \opt{attribute-specifier-seq} identifier \terminal{:}\br + \opt{attribute-specifier-seq} \keyword{case} constant-expression \terminal{:}\br + \opt{attribute-specifier-seq} \keyword{default} \terminal{:} +\end{bnf} \begin{bnf} \nontermdef{labeled-statement}\br - \opt{attribute-specifier-seq} identifier \terminal{:} statement\br - \opt{attribute-specifier-seq} \keyword{case} constant-expression \terminal{:} statement\br - \opt{attribute-specifier-seq} \keyword{default} \terminal{:} statement + label statement \end{bnf} The optional \grammarterm{attribute-specifier-seq} appertains to the label. @@ -139,13 +145,25 @@ \indextext{label!scope of}% No two labels in a function shall have the same \grammarterm{identifier}. A label can be used in a \tcode{goto} statement -before its introduction by a \grammarterm{labeled-statement}. +before its introduction. \pnum \indextext{label!\idxcode{case}}% \indextext{label!\idxcode{default}}% Case labels and default labels shall occur only in \keyword{switch} statements. +\pnum +A \defnadj{control-flow-limited}{statement} is a statement \tcode{S} for which: +\begin{itemize} +\item + a \keyword{case} or \keyword{default} label appearing within \tcode{S} shall + be associated with a \keyword{switch} statement\iref{stmt.switch} within + \tcode{S}, and +\item + a label declared in \tcode{S} shall only be referred to by a + statement\iref{stmt.goto} in \tcode{S}. +\end{itemize} + \rSec1[stmt.expr]{Expression statement}% \indextext{statement!expression} @@ -169,8 +187,7 @@ a \defn{null statement}. \begin{note} Most statements are expression statements --- usually assignments or -function calls. A null statement is useful to carry a label just before -the \tcode{\}} of a compound statement and to supply a null body to an +function calls. A null statement is useful to supply a null body to an iteration statement such as a \keyword{while} statement\iref{stmt.while}. \end{note} @@ -184,7 +201,7 @@ \begin{bnf} \nontermdef{compound-statement}\br - \terminal{\{} \opt{statement-seq} \terminal{\}} + \terminal{\{} \opt{statement-seq} \opt{label-seq} \terminal{\}} \end{bnf} \begin{bnf} @@ -193,6 +210,16 @@ statement-seq statement \end{bnf} +\begin{bnf} +\nontermdef{label-seq}\br + label\br + label-seq label +\end{bnf} + +A label at the end of a \grammarterm{compound-statement} +is treated as if it were followed by a null statement. + +\pnum \begin{note} A compound statement defines a block scope\iref{basic.scope}. A declaration is a \grammarterm{statement}\iref{stmt.dcl}. @@ -262,6 +289,8 @@ enclosing templated entity\iref{temp.pre}, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated. +Each substatement of a constexpr if statement is a control-flow-limited +statement\iref{stmt.label}. \begin{example} \begin{codeblock} if constexpr (sizeof(int[2])) {} // OK, narrowing allowed @@ -271,12 +300,6 @@ Odr-uses\iref{term.odr.use} in a discarded statement do not require an entity to be defined. \end{note} -A \keyword{case} or \keyword{default} label appearing within such an -\keyword{if} statement shall be associated with a \keyword{switch} -statement\iref{stmt.switch} within the same \keyword{if} statement. -A label\iref{stmt.label} declared in a substatement of a constexpr if -statement shall only be referred to by a statement\iref{stmt.goto} in -the same substatement. \begin{example} \begin{codeblock} template void g(T&& p, Rest&& ...rs) { @@ -349,12 +372,8 @@ \end{note} Otherwise, if the \keyword{else} part of the selection statement is present, then the second substatement is executed. -A \keyword{case} or \keyword{default} label -appearing within such an \keyword{if} statement -shall be associated with a \keyword{switch} statement -within the same \keyword{if} statement. -A label declared in a substatement of a consteval if statement -shall only be referred to by a statement in the same substatement. +Each substatement of a consteval if statement is a control-flow-limited +statement\iref{stmt.label}. \pnum An \keyword{if} statement of the form diff --git a/source/strings.tex b/source/strings.tex index d163c25419..d9bd3cef43 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -20,7 +20,7 @@ \begin{libsumtab}[x{2.1in}]{Strings library summary}{strings.summary} \ref{char.traits} & Character traits & \tcode{} \\ \ref{string.view} & String view classes & \tcode{} \\ \rowsep -\ref{string.classes} & String classes & \\ \rowsep +\ref{string.classes} & String classes & \tcode{} \\ \rowsep \ref{c.strings} & Null-terminated sequence utilities & \tcode{}, \tcode{}, \tcode{}, \tcode{}, \tcode{}, \tcode{} \\ @@ -151,7 +151,7 @@ \tcode{X::find(p,n,c)} & \tcode{const X::char_type*} & \returns the smallest \tcode{q} in \tcode{[p,p+n)} such that -\tcode{X::eq(*q,c)} is \tcode{true}, zero otherwise. & linear \\ \rowsep +\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 @@ -526,7 +526,7 @@ \pnum \begin{note} The library provides implicit conversions from \tcode{const charT*} and \tcode{std::basic_string} to \tcode{std::basic_string_view} so that user code can accept just \tcode{std::basic_string_view} as a non-templated parameter wherever a sequence of characters is expected. -User-defined types can define their own implicit conversions to \tcode{std::basic_string_view} in order to interoperate with these functions. +User-defined types can define their own implicit conversions to \tcode{std::basic_string_view} in order to interoperate with these functions. \end{note} \rSec2[string.view.synop]{Header \tcode{} synopsis} @@ -643,7 +643,7 @@ template constexpr basic_string_view(It begin, End end); template - constexpr basic_string_view(R&& r); + constexpr explicit basic_string_view(R&& r); // \ref{string.view.iterators}, iterator support constexpr const_iterator begin() const noexcept; @@ -850,7 +850,7 @@ \indexlibraryctor{basic_string_view}% \begin{itemdecl} template - constexpr basic_string_view(R&& r); + constexpr explicit basic_string_view(R&& r); \end{itemdecl} \begin{itemdescr} @@ -888,6 +888,33 @@ Any exception thrown by \tcode{ranges::data(r)} and \tcode{ranges::size(r)}. \end{itemdescr} +\rSec3[string.view.deduct]{Deduction guides} + +\begin{itemdecl} +template + basic_string_view(It, End) -> basic_string_view>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{It} satisfies \libconcept{contiguous_iterator}. +\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + basic_string_view(R&&) -> basic_string_view>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. +\end{itemdescr} + \rSec3[string.view.iterators]{Iterator support} \indexlibrarymember{const_iterator}{basic_string_view}% @@ -1563,33 +1590,6 @@ Otherwise, returns \tcode{npos}. \end{itemdescr} -\rSec2[string.view.deduct]{Deduction guides} - -\begin{itemdecl} -template - basic_string_view(It, End) -> basic_string_view>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item \tcode{It} satisfies \libconcept{contiguous_iterator}. -\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. -\end{itemize} -\end{itemdescr} - -\begin{itemdecl} -template - basic_string_view(R&&) -> basic_string_view>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. -\end{itemdescr} - \rSec2[string.view.comparison]{Non-member comparison functions} \pnum @@ -1972,16 +1972,11 @@ // \ref{basic.string.hash}, hash support template struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; + template struct hash, A>>; + template struct hash, A>>; + template struct hash, A>>; + template struct hash, A>>; + template struct hash, A>>; inline namespace literals { inline namespace string_literals { @@ -2071,6 +2066,10 @@ const Allocator& a = Allocator()); constexpr basic_string(const basic_string& str, size_type pos, size_type n, const Allocator& a = Allocator()); + constexpr basic_string(basic_string&& str, size_type pos, + const Allocator& a = Allocator()); + constexpr basic_string(basic_string&& str, size_type pos, size_type n, + const Allocator& a = Allocator()); template constexpr basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); @@ -2292,7 +2291,8 @@ constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const; constexpr size_type find_last_not_of(charT c, size_type pos = npos) const noexcept; - constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; + constexpr basic_string substr(size_type pos = 0, size_type n = npos) const &; + constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; template constexpr int compare(const T& t) const noexcept(@\seebelow@); @@ -2458,15 +2458,43 @@ const Allocator& a = Allocator()); constexpr basic_string(const basic_string& str, size_type pos, size_type n, const Allocator& a = Allocator()); +constexpr basic_string(basic_string&& str, size_type pos, + const Allocator& a = Allocator()); +constexpr basic_string(basic_string&& str, size_type pos, size_type n, + const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} +\pnum +Let +\begin{itemize} +\item +\tcode{s} be the value of \tcode{str} prior to this call and +\item +\tcode{rlen} be \tcode{pos + min(n, s.size() - pos)} +for the overloads with parameter \tcode{n}, and +\tcode{s.size()} otherwise. +\end{itemize} + \pnum \effects -Let \tcode{n} be \tcode{npos} for the first overload. Equivalent to: -\begin{codeblock} -basic_string(basic_string_view(str).substr(pos, n), a) -\end{codeblock} +Constructs an object +whose initial value is the range \range{s.data() + pos}{s.data() + rlen}. + +\pnum +\throws +\tcode{out_of_range} if \tcode{pos > s.size()}. + +\pnum +\remarks +For the overloads with a \tcode{basic_string\&\&} parameter, +\tcode{str} is left in a valid but unspecified state. + +\pnum +\recommended +For the overloads with a \tcode{basic_string\&\&} parameter, +implementations should avoid allocation +if \tcode{s.get_allocator() == a} is \tcode{true}. \end{itemdescr} \indexlibraryctor{basic_string}% @@ -4427,24 +4455,24 @@ \indexlibrarymember{substr}{basic_string}% \begin{itemdecl} -constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; +constexpr basic_string substr(size_type pos = 0, size_type n = npos) const &; \end{itemdecl} \begin{itemdescr} \pnum \effects -Determines the effective length \tcode{rlen} of the string to copy as the smaller of \tcode{n} and -\tcode{size() - pos}. +Equivalent to: \tcode{return basic_string(*this, pos, n);} +\end{itemdescr} -\pnum -\returns -\tcode{basic_string(data()+pos, rlen)}. +\indexlibrarymember{substr}{basic_string}% +\begin{itemdecl} +constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; +\end{itemdecl} +\begin{itemdescr} \pnum -\throws -\tcode{out_of_range} -if -\tcode{pos > size()}. +\effects +Equivalent to: \tcode{return basic_string(std::move(*this), pos, n);} \end{itemdescr} \rSec4[string.compare]{\tcode{basic_string::compare}} @@ -5290,25 +5318,13 @@ \rSec2[basic.string.hash]{Hash support} -\indexlibrarymember{hash}{string}% -\indexlibrarymember{hash}{u16string}% -\indexlibrarymember{hash}{u32string}% -\indexlibrarymember{hash}{wstring}% -\indexlibrarymember{hash}{pmr::string}% -\indexlibrarymember{hash}{pmr::u16string}% -\indexlibrarymember{hash}{pmr::u32string}% -\indexlibrarymember{hash}{pmr::wstring}% -\begin{itemdecl} -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; +\indexlibrarymember{hash}{basic_string}% +\begin{itemdecl} +template struct hash, A>>; +template struct hash, A>>; +template struct hash, A>>; +template struct hash, A>>; +template struct hash, A>>; \end{itemdecl} \begin{itemdescr} diff --git a/source/support.tex b/source/support.tex index 40ceef1aae..3ea8ec79c5 100644 --- a/source/support.tex +++ b/source/support.tex @@ -27,6 +27,7 @@ \ref{support.limits} & Implementation properties & \tcode{}, \tcode{}, \tcode{}, \tcode{} \\ \rowsep \ref{cstdint} & Integer types & \tcode{} \\ \rowsep +\ref{stdfloat.syn} & Header \libheader{stdfloat} synopsis & \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 @@ -51,6 +52,7 @@ \indexlibraryglobal{nullptr_t}% \indexlibraryglobal{byte}% \begin{codeblock} +// all freestanding namespace std { using ptrdiff_t = @\seebelow@; using size_t = @\seebelow@; @@ -148,13 +150,13 @@ \indexlibraryglobal{wctomb}% \begin{codeblock} namespace std { - using size_t = @\seebelow@; + using size_t = @\seebelow@; // freestanding using div_t = @\seebelow@; using ldiv_t = @\seebelow@; using lldiv_t = @\seebelow@; } -#define NULL @\seebelow@ +#define NULL @\seebelow@ // freestanding #define EXIT_FAILURE @\seebelow@ #define EXIT_SUCCESS @\seebelow@ #define RAND_MAX @\seebelow@ @@ -162,20 +164,20 @@ namespace std { // Exposition-only function type aliases - extern "C" using @\placeholdernc{c-atexit-handler}@ = void(); // \expos - extern "C++" using @\placeholdernc{atexit-handler}@ = void(); // \expos - extern "C" using @\placeholdernc{c-compare-pred}@ = int(const void*, const void*); // \expos - extern "C++" using @\placeholdernc{compare-pred}@ = int(const void*, const void*); // \expos + extern "C" using @\placeholdernc{c-atexit-handler}@ = void(); // \expos + extern "C++" using @\placeholdernc{atexit-handler}@ = void(); // \expos + extern "C" using @\placeholdernc{c-compare-pred}@ = int(const void*, const void*); // \expos + extern "C++" using @\placeholdernc{compare-pred}@ = int(const void*, const void*); // \expos // \ref{support.start.term}, start and termination - [[noreturn]] void abort() noexcept; - int atexit(@\placeholder{c-atexit-handler}@* func) noexcept; - int atexit(@\placeholder{atexit-handler}@* func) noexcept; - int at_quick_exit(@\placeholder{c-atexit-handler}@* func) noexcept; - int at_quick_exit(@\placeholder{atexit-handler}@* func) noexcept; - [[noreturn]] void exit(int status); - [[noreturn]] void _Exit(int status) noexcept; - [[noreturn]] void quick_exit(int status) noexcept; + [[noreturn]] void abort() noexcept; // freestanding + int atexit(@\placeholder{c-atexit-handler}@* func) noexcept; // freestanding + int atexit(@\placeholder{atexit-handler}@* func) noexcept; // freestanding + int at_quick_exit(@\placeholder{c-atexit-handler}@* func) noexcept; // freestanding + int at_quick_exit(@\placeholder{atexit-handler}@* func) noexcept; // freestanding + [[noreturn]] void exit(int status); // freestanding + [[noreturn]] void _Exit(int status) noexcept; // freestanding + [[noreturn]] void quick_exit(int status) noexcept; // freestanding char* getenv(const char* name); int system(const char* string); @@ -222,9 +224,7 @@ constexpr int abs(int j); constexpr long int abs(long int j); constexpr long long int abs(long long int j); - constexpr float abs(float j); - constexpr double abs(double j); - constexpr long double abs(long double j); + constexpr @\placeholder{floating-point-type}@ abs(@\placeholder{floating-point-type}@ j); constexpr long int labs(long int j); constexpr long long int llabs(long long int j); @@ -551,7 +551,10 @@ \end{note} \begin{codeblock} +// all freestanding #define @\defnlibxname{cpp_lib_addressof_constexpr}@ 201603L // also in \libheader{memory} +#define @\defnlibxname{cpp_lib_algorithm_iterator_requirements}@ 202207L + // also in \libheader{algorithm}, \libheader{numeric}, \libheader{memory} #define @\defnlibxname{cpp_lib_allocate_at_least}@ 202106L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_allocator_traits_is_always_equal}@ 201411L // also in \libheader{memory}, \libheader{scoped_allocator}, \libheader{string}, \libheader{deque}, \libheader{forward_list}, \libheader{list}, \libheader{vector}, @@ -588,8 +591,10 @@ #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_complex_udls}@ 201309L // also in \libheader{complex} -#define @\defnlibxname{cpp_lib_concepts}@ 202002L // also in \libheader{concepts} +#define @\defnlibxname{cpp_lib_concepts}@ 202207L // also in \libheader{concepts}, \libheader{compare} #define @\defnlibxname{cpp_lib_constexpr_algorithms}@ 201806L // also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_constexpr_bitset}@ 202202L // also in \libheader{bitset} +#define @\defnlibxname{cpp_lib_constexpr_charconv}@ 202207L // also in \libheader{charconv} #define @\defnlibxname{cpp_lib_constexpr_cmath}@ 202202L // also in \libheader{cmath}, \libheader{cstdlib} #define @\defnlibxname{cpp_lib_constexpr_complex}@ 201711L // also in \libheader{complex} #define @\defnlibxname{cpp_lib_constexpr_dynamic_alloc}@ 201907L // also in \libheader{memory} @@ -617,8 +622,12 @@ #define @\defnlibxname{cpp_lib_execution}@ 201902L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_expected}@ 202202L // also in \libheader{expected} #define @\defnlibxname{cpp_lib_filesystem}@ 201703L // also in \libheader{filesystem} -#define @\defnlibxname{cpp_lib_format}@ 202110L // also in \libheader{format} +#define @\defnlibxname{cpp_lib_find_last}@ 202207L // also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_flat_map}@ 202207L // also in \libheader{flat_map} +#define @\defnlibxname{cpp_lib_format}@ 202207L // also in \libheader{format} +#define @\defnlibxname{cpp_lib_forward_like}@ 202207L // also in \libheader{utility} #define @\defnlibxname{cpp_lib_gcd_lcm}@ 201606L // also in \libheader{numeric} +#define @\defnlibxname{cpp_lib_generator}@ 202207L // also in \libheader{generator} #define @\defnlibxname{cpp_lib_generic_associative_lookup}@ 201304L // also in \libheader{map}, \libheader{set} #define @\defnlibxname{cpp_lib_generic_unordered_lookup}@ 201811L // also in \libheader{unordered_map}, \libheader{unordered_set} @@ -634,6 +643,7 @@ #define @\defnlibxname{cpp_lib_interpolate}@ 201902L // also in \libheader{cmath}, \libheader{numeric} #define @\defnlibxname{cpp_lib_invoke}@ 201411L // also in \libheader{functional} #define @\defnlibxname{cpp_lib_invoke_r}@ 202106L // also in \libheader{functional} +#define @\defnlibxname{cpp_lib_ios_noreplace}@ 202207L // also in \libheader{ios} #define @\defnlibxname{cpp_lib_is_aggregate}@ 201703L // also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_constant_evaluated}@ 201811L // also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_final}@ 201402L // also in \libheader{type_traits} @@ -655,7 +665,10 @@ #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_memory_resource}@ 201603L // also in \libheader{memory_resource} +#define @\defnlibxname{cpp_lib_modules}@ 202207L +#define @\defnlibxname{cpp_lib_move_iterator_concept}@ 202207L // also in \libheader{iterator} #define @\defnlibxname{cpp_lib_move_only_function}@ 202110L // also in \libheader{functional} #define @\defnlibxname{cpp_lib_node_extract}@ 201606L // also in \libheader{map}, \libheader{set}, \libheader{unordered_map}, \libheader{unordered_set} @@ -668,15 +681,23 @@ #define @\defnlibxname{cpp_lib_out_ptr}@ 202106L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_parallel_algorithm}@ 201603L // also in \libheader{algorithm}, \libheader{numeric} #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_quoted_string_io}@ 201304L // also in \libheader{iomanip} -#define @\defnlibxname{cpp_lib_ranges}@ 202202L +#define @\defnlibxname{cpp_lib_ranges}@ 202207L // also in \libheader{algorithm}, \libheader{functional}, \libheader{iterator}, \libheader{memory}, \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_as_const}@ 202207L // also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_as_rvalue}@ 202207L // also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_cartesian_product}@ 202207L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_chunk}@ 202202L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_chunk_by}@ 202202L // also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_contains}@ 202207L // also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_ranges_fold}@ 202207L // also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_ranges_iota}@ 202202L // also in \libheader{numeric} #define @\defnlibxname{cpp_lib_ranges_join_with}@ 202202L // also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_repeat}@ 202207L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_slide}@ 202202L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_starts_ends_with}@ 202106L // also in \libheader{algorithm} +#define @\defnlibxname{cpp_lib_ranges_stride}@ 202207L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_to_container}@ 202202L // also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_zip}@ 202110L // also in \libheader{ranges}, \libheader{tuple}, \libheader{utility} #define @\defnlibxname{cpp_lib_raw_memory_algorithms}@ 201606L // also in \libheader{memory} @@ -698,6 +719,7 @@ #define @\defnlibxname{cpp_lib_spanstream}@ 202106L // also in \libheader{spanstream} #define @\defnlibxname{cpp_lib_ssize}@ 201902L // also in \libheader{iterator} #define @\defnlibxname{cpp_lib_stacktrace}@ 202011L // also in \libheader{stacktrace} +#define @\defnlibxname{cpp_lib_start_lifetime_as}@ 202207L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_starts_ends_with}@ 201711L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_stdatomic_h}@ 202011L // also in \libheader{stdatomic.h} #define @\defnlibxname{cpp_lib_string_contains}@ 202011L // also in \libheader{string}, \libheader{string_view} @@ -712,6 +734,8 @@ #define @\defnlibxname{cpp_lib_to_underlying}@ 202102L // also in \libheader{utility} #define @\defnlibxname{cpp_lib_transformation_trait_aliases}@ 201304L // also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_transparent_operators}@ 201510L // also in \libheader{memory}, \libheader{functional} +#define @\defnlibxname{cpp_lib_tuple_like}@ 202207L + // also in \libheader{utility}, \libheader{tuple}, \libheader{map}, \libheader{unordered_map} #define @\defnlibxname{cpp_lib_tuple_element_t}@ 201402L // also in \libheader{tuple} #define @\defnlibxname{cpp_lib_tuples_by_type}@ 201304L // also in \libheader{utility}, \libheader{tuple} #define @\defnlibxname{cpp_lib_type_identity}@ 201806L // also in \libheader{type_traits} @@ -733,6 +757,7 @@ \indexlibraryglobal{float_denorm_style}% \begin{codeblock} +// all freestanding namespace std { // \ref{fp.style}, floating-point type properties enum float_round_style; @@ -1436,11 +1461,15 @@ \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 ISO/IEC/IEEE 60559. \begin{footnote} -ISO/IEC/IEEE 60559:2011 is the same as IEEE 754-2008. +ISO/IEC/IEEE 60559:2020 is the same as IEEE 754-2019. \end{footnote} +\begin{note} +The value is \tcode{true} for any of the types +\tcode{float16_t}, \tcode{float32_t}, \tcode{float64_t}, or \tcode{float128_t}, +if present\iref{basic.extended.fp}. +\end{note} \pnum Meaningful for all floating-point types. @@ -1690,6 +1719,7 @@ \indexlibraryglobal{LLONG_MAX}% \indexlibraryglobal{ULLONG_MAX}% \begin{codeblock} +// all freestanding #define CHAR_BIT @\seebelow@ #define SCHAR_MIN @\seebelow@ #define SCHAR_MAX @\seebelow@ @@ -1765,6 +1795,7 @@ \indexlibraryglobal{LDBL_MIN_EXP}% \indexlibraryglobal{LDBL_TRUE_MIN}% \begin{codeblock} +// all freestanding #define FLT_ROUNDS @\seebelow@ #define FLT_EVAL_METHOD @\seebelow@ #define FLT_HAS_SUBNORM @\seebelow@ @@ -1855,6 +1886,7 @@ \indexlibraryglobal{uintmax_t}% \indexlibraryglobal{uintptr_t}% \begin{codeblock} +// all freestanding namespace std { using int8_t = @\textit{signed integer type}@; // optional using int16_t = @\textit{signed integer type}@; // optional @@ -1965,6 +1997,29 @@ respectively. \end{note} +\rSec1[stdfloat.syn]{Header \tcode{} synopsis} + +\indexheader{stdfloat}% +\begin{codeblock} +namespace std { + #if defined(__STDCPP_FLOAT16_T__) + using float16_t = @\UNSP{\impldef{type of \tcode{std::float16_t}}}@; // see \ref{basic.extended.fp} + #endif + #if defined(__STDCPP_FLOAT32_T__) + using float32_t = @\UNSP{\impldef{type of \tcode{std::float32_t}}}@; // see \ref{basic.extended.fp} + #endif + #if defined(__STDCPP_FLOAT64_T__) + using float64_t = @\UNSP{\impldef{type of \tcode{std::float64_t}}}@; // see \ref{basic.extended.fp} + #endif + #if defined(__STDCPP_FLOAT128_T__) + using float128_t = @\UNSP{\impldef{type of \tcode{std::float128_t}}}@; // see \ref{basic.extended.fp} + #endif + #if defined(__STDCPP_BFLOAT16_T__) + using bfloat16_t = @\UNSP{\impldef{type of \tcode{std::bfloat16_t}}}@; // see \ref{basic.extended.fp} + #endif +} +\end{codeblock} + \rSec1[support.start.term]{Startup and termination} \pnum @@ -2189,6 +2244,7 @@ \rSec2[new.syn]{Header \tcode{} synopsis} \begin{codeblock} +// all freestanding namespace std { // \ref{alloc.errors}, storage allocation errors class bad_alloc; @@ -3010,8 +3066,9 @@ An object \placeholder{X} that is within its lifetime\iref{basic.life} and whose type is similar\iref{conv.qual} to \tcode{T} is located at the address \placeholder{A}. -All bytes of storage that would be reachable through the result -are reachable through \tcode{p} (see below). +All bytes of storage that would be +reachable through\iref{basic.compound} the result +are reachable through \tcode{p}. \pnum \returns @@ -3023,14 +3080,6 @@ may be used in a core constant expression if and only if the (converted) value of its argument may be used in place of the function invocation. -A byte of storage \placeholder{b} is -reachable through a pointer value -that points to an object \placeholder{Y} -if there is an object \placeholder{Z}, -pointer-interconvertible with \placeholder{Y}, -such that \placeholder{b} is within the storage occupied by -\placeholder{Z}, or -the immediately-enclosing array object if \placeholder{Z} is an array element. \pnum \begin{note} @@ -3122,6 +3171,7 @@ \indexlibraryglobal{bad_cast}% \indexlibraryglobal{bad_typeid}% \begin{codeblock} +// all freestanding namespace std { class type_info; class bad_cast; @@ -3306,6 +3356,7 @@ that provides a means to obtain source location information. \begin{codeblock} +// all freestanding namespace std { struct source_location; } @@ -3478,7 +3529,7 @@ \begin{itemdescr} \pnum -\Fundesc{Effects} +\effects The data members are initialized with valid but unspecified values. \end{itemdescr} @@ -3531,6 +3582,7 @@ \rSec2[exception.syn]{Header \tcode{} synopsis} \begin{codeblock} +// all freestanding namespace std { class exception; class bad_exception; @@ -4043,6 +4095,7 @@ \indexlibraryglobal{end}% \begin{codeblock} +// all freestanding namespace std { template class initializer_list { public: @@ -4178,6 +4231,7 @@ \indexlibraryglobal{is_gteq}% \indexlibraryglobal{common_comparison_category_t}% \begin{codeblock} +// all freestanding namespace std { // \ref{cmp.categories}, comparison category types class partial_ordering; @@ -4277,10 +4331,10 @@ \pnum The \tcode{partial_ordering} type is typically used as the result type of a three-way comparison operator\iref{expr.spaceship} -that (a) admits all of the six -two-way comparison operators\iref{expr.rel,expr.eq}, -(b) does not imply substitutability, -and (c) permits two values to be incomparable. +for a type that admits +all of the six two-way comparison operators\iref{expr.rel,expr.eq}, +for which equality need not imply substitutability, +and that permits two values to be incomparable.% \begin{footnote} That is, \tcode{a < b}, \tcode{a == b}, and \tcode{a > b} might all be \tcode{false}. \end{footnote} @@ -4395,9 +4449,9 @@ \pnum The \tcode{weak_ordering} type is typically used as the result type of a three-way comparison operator\iref{expr.spaceship} -that (a) admits all of the six -two-way comparison operators\iref{expr.rel,expr.eq}, -and (b) does not imply substitutability. +for a type that admits +all of the six two-way comparison operators\iref{expr.rel,expr.eq} +and for which equality need not imply substitutability. \indexlibraryglobal{weak_ordering}% \indexlibrarymember{less}{weak_ordering}% @@ -4520,9 +4574,9 @@ \pnum The \tcode{strong_ordering} type is typically used as the result type of a three-way comparison operator\iref{expr.spaceship} -that (a) admits all of the six -two-way comparison operators\iref{expr.rel,expr.eq}, -and (b) does imply substitutability. +for a type that admits +all of the six two-way comparison operators\iref{expr.rel,expr.eq} +and for which equality does imply substitutability. \indexlibraryglobal{strong_ordering}% \indexlibrarymember{less}{strong_ordering}% @@ -4780,7 +4834,7 @@ concept @\deflibconcept{three_way_comparable_with}@ = @\libconcept{three_way_comparable}@ && @\libconcept{three_way_comparable}@ && - @\libconcept{common_reference_with}@&, const remove_reference_t&> && + @\exposconcept{comparison-common-type-with}@ && @\libconcept{three_way_comparable}@< common_reference_t&, const remove_reference_t&>, Cat> && @\exposconcept{weakly-equality-comparable-with}@ && @@ -4792,11 +4846,17 @@ \end{codeblock} \pnum -Let \tcode{t} and \tcode{u} be lvalues +Let \tcode{t} and \tcode{t2} be lvalues +denoting distinct equal objects of types \tcode{const remove_reference_t} and -\tcode{const remove_reference_t}, respectively. +\tcode{remove_cvref_t}, respectively, and +let \tcode{u} and \tcode{u2} be lvalues denoting distinct equal objects +of types \tcode{const remove_reference_t} and +\tcode{remove_cvref_t}, respectively. Let \tcode{C} be \tcode{common_reference_t\&, const remove_reference_t\&>}. +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: \begin{itemize} @@ -4809,7 +4869,8 @@ \item \tcode{(t <=> u != 0) == bool(t != u)} is \tcode{true}, \item - \tcode{Cat(t <=> u) == Cat(C(t) <=> C(u))} is \tcode{true}, + \tcode{Cat(t <=> u) == Cat(\exposid{CONVERT_TO_LVALUE}(t2) <=> +\exposid{CONVERT_TO_LVALUE}(u2))} is \tcode{true}, \item \tcode{(t <=> u < 0) == bool(t < u)} is \tcode{true}, \item @@ -5080,6 +5141,7 @@ \indexheader{coroutine}% \indexlibraryglobal{noop_coroutine_handle}% \begin{codeblock} +// all freestanding #include // see \ref{compare.syn} namespace std { @@ -5705,6 +5767,7 @@ \indexlibraryglobal{va_end}% \indexlibraryglobal{va_arg}% \begin{codeblock} +// all freestanding namespace std { using va_list = @\seebelow@; } diff --git a/source/templates.tex b/source/templates.tex index dce8fc693d..873ad16891 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -1589,8 +1589,8 @@ called the \defn{parameter mapping}\iref{temp.constr.decl}. \begin{note} Atomic constraints are formed by constraint normalization\iref{temp.constr.normal}. -\tcode{E} is never a logical \logop{AND} expression\iref{expr.log.and} -nor a logical \logop{OR} expression\iref{expr.log.or}. +\tcode{E} is never a logical \logop{and} expression\iref{expr.log.and} +nor a logical \logop{or} expression\iref{expr.log.or}. \end{note} \pnum @@ -1728,7 +1728,7 @@ of that expression. \item Otherwise, the associated constraints are the normal form of a logical -\logop{AND} expression\iref{expr.log.and} whose operands are in the +\logop{and} expression\iref{expr.log.and} whose operands are in the following order: \begin{itemize} \item @@ -1897,7 +1897,7 @@ template concept C1 = sizeof(T) == 1; template concept C2 = C1 && 1 == 2; template concept C3 = requires { typename T::type; }; -template concept C4 = requires (T x) { ++x; } +template concept C4 = requires (T x) { ++x; }; template void f1(U); // \#1 template void f2(U); // \#2 @@ -2179,7 +2179,7 @@ which is unrelated to the templated function definition or to any other -default arguments +default arguments, \grammarterm{type-constraint}{s}, \grammarterm{requires-clause}{s}, or @@ -5072,13 +5072,17 @@ Expressions of the following forms are type-dependent only if the type specified by the \grammarterm{type-id}, -\grammarterm{simple-type-specifier} +\grammarterm{simple-type-specifier}, +\grammarterm{typename-specifier}, or \grammarterm{new-type-id} is dependent, even if any subexpression is type-dependent: \begin{ncsimplebnf} simple-type-specifier \terminal{(} \opt{expression-list} \terminal{)}\br +simple-type-specifier braced-init-list\br +typename-specifier \terminal{(} \opt{expression-list} \terminal{)}\br +typename-specifier braced-init-list\br \opt{\terminal{::}} \keyword{new} \opt{new-placement} new-type-id \opt{new-initializer}\br \opt{\terminal{::}} \keyword{new} \opt{new-placement} \terminal{(} type-id \terminal{)} \opt{new-initializer}\br \keyword{dynamic_cast} \terminal{<} type-id \terminal{>} \terminal{(} expression \terminal{)}\br @@ -5780,7 +5784,7 @@ \end{example} However, for the purpose of determining whether an instantiated redeclaration is valid according to~\ref{basic.def.odr} and \ref{class.mem}, -a declaration that corresponds to a definition in the template +an instantiated declaration that corresponds to a definition in the template is considered to be a definition. \begin{example} \begin{codeblock} @@ -5971,7 +5975,7 @@ the same template parameters and the same access as that of the function template \tcode{f} used at that point, except that the scope in which a closure type is -declared\iref{expr.prim.lambda.closure} -- and therefore its associated namespaces -- +declared\iref{expr.prim.lambda.closure} --- and therefore its associated namespaces --- remain as determined from the context of the definition for the default argument. This analysis is called @@ -6826,7 +6830,9 @@ A trailing template parameter pack\iref{temp.variadic} not otherwise deduced will be deduced as an empty sequence of template arguments. \end{note} -If all of the template arguments can be deduced, they may all be omitted; +If all of the template arguments can be +deduced or obtained from default \grammarterm{template-argument}{s}, +they may all be omitted; in this case, the empty template argument list \tcode{<>} itself may also be omitted. \begin{example} @@ -8013,8 +8019,8 @@ \begin{itemize} \item -A function type includes the types of each of the function parameters -and the return type. +A function type includes the types of each of the function parameters, +the return type, and its exception specification. \item A pointer-to-member type includes the type of the class object pointed to and the type of the member pointed to. @@ -8167,6 +8173,25 @@ } \end{codeblock} +Here is an example where the exception specification of a function type +is deduced: + +\begin{codeblock} +template void f1(void (*)() noexcept(E)); +template struct A { }; +template void f2(void (*)(A) noexcept(B)); + +void g1(); +void g2() noexcept; +void g3(A); + +void h() { + f1(g1); // OK, \tcode{E} is \tcode{false} + f1(g2); // OK, \tcode{E} is \tcode{true} + f2(g3); // error: \tcode{B} deduced as both \tcode{true} and \tcode{false} +} +\end{codeblock} + Here is an example where a qualification conversion applies between the argument type on the function call and the deduced template argument type: @@ -8199,7 +8224,7 @@ A template type argument \tcode{T}, a template template argument -\tcode{TT} +\tcode{TT}, or a template non-type argument \tcode{i} can be deduced if @@ -8208,44 +8233,49 @@ \tcode{A} have one of the following forms: \begin{codeblock} -T -@\cv{}@ T +@\opt{\cv{}}@ T T* T& T&& -T[@\placeholder{integer-constant}@] -@\grammarterm{template-name}@ @\textrm{(where \tcode{\grammarterm{template-name}} refers to a class template)}@ -@\placeholder{type}@(T) -T() -T(T) -T @\placeholder{type}@::* -@\placeholder{type}@ T::* -T T::* -T (@\placeholder{type}@::*)() -@\placeholder{type}@ (T::*)() -@\placeholder{type}@ (@\placeholder{type}@::*)(T) -@\placeholder{type}@ (T::*)(T) -T (@\placeholder{type}@::*)(T) -T (T::*)() -T (T::*)(T) -@\placeholder{type}@[i] -@\grammarterm{template-name}@ @\textrm{(where \tcode{\grammarterm{template-name}} refers to a class template)}@ -TT -TT -TT<> +@\opt{T}@[@\opt{i}@] +@\opt{T}@(@\opt{T}@) noexcept(@\opt{i}@) +@\opt{T}@ @\opt{T}@::* +@\opt{TT}@ +@\opt{TT}@ +@\opt{TT}@ +@\opt{TT}@<> \end{codeblock} where -\tcode{(T)} -represents -a parameter-type-list\iref{dcl.fct} -where at least one parameter type contains a -\tcode{T}, -and -\tcode{()} -represents -a parameter-type-list -where no parameter type contains a -\tcode{T}. +\begin{itemize} +\item +\tcode{\opt{T}} represents a type or parameter-type-list that either +satisfies these rules recursively, +is a non-deduced context in \tcode{P} or \tcode{A}, or +is the same non-dependent type in \tcode{P} and \tcode{A}, + +\item +\tcode{\opt{TT}} represents either a class template or +a template template parameter, + +\item +\tcode{\opt{i}} represents an expression that either +is an \tcode{i}, +is value-dependent in \tcode{P} or \tcode{A}, or +has the same constant value in \tcode{P} and \tcode{A}, and + +\item +\tcode{\keyword{noexcept}(\opt{i})} represents an +exception specification\iref{except.spec} +in which the (possibly-implicit, see~\ref{dcl.fct}) +\grammarterm{noexcept-specifier}'s operand +satisfies the rules for an \tcode{\opt{i}} above. +\end{itemize} + +\begin{note} +If a type matches such a form but contains no +\tcode{T}s, \tcode{i}s, or \tcode{TT}s, deduction is not possible. +\end{note} + Similarly, \tcode{} represents template argument lists where at least one argument contains a @@ -8417,6 +8447,21 @@ \end{codeblock} \end{example} +\pnum +The type of \tcode{B} in the \grammarterm{noexcept-specifier} +\tcode{\keyword{noexcept}(B)} of a function type is \tcode{bool}. +\begin{example} +\begin{codeblock} +template struct A { }; +template struct B; +template struct B { + A ax; +}; +void f_nothrow() noexcept; +B bn; // OK, type of \tcode{X} deduced as \tcode{bool} +\end{codeblock} +\end{example} + \pnum \begin{example} \begin{codeblock} @@ -8509,6 +8554,8 @@ \tcode{true} because the array bound will be nonzero. \end{footnote} +If \tcode{P} has a form that includes \tcode{\keyword{noexcept}(i)} and +the type of \tcode{i} is not \tcode{bool}, deduction fails. \begin{example} \begin{codeblock} template class A { @\commentellip@ }; @@ -8603,7 +8650,7 @@ X x1; // uses primary template X x2; // uses partial specialization; \tcode{ArgTypes} contains \tcode{float}, \tcode{double} X x3; // uses primary template -Y<> y1; // use primary template; \tcode{Types} is empty +Y<> y1; // uses primary template; \tcode{Types} is empty Y y2; // uses partial specialization; \tcode{T} is \tcode{int\&}, \tcode{Types} contains \tcode{float}, \tcode{double} Y y3; // uses primary template; \tcode{Types} contains \tcode{int}, \tcode{float}, \tcode{double} int fv = f(g); // OK; \tcode{Types} contains \tcode{int}, \tcode{float} @@ -8748,11 +8795,11 @@ template void f(T); // declaration void g() { - f("Annemarie"); // call of \tcode{f} + f("Annemarie"); // calls \tcode{f} } \end{codeblock} -The call of +The call to \tcode{f} is well-formed even if the template \tcode{f} diff --git a/source/threads.tex b/source/threads.tex index b2a90ea8d3..a383dd8181 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -14,7 +14,7 @@ \ref{thread.stoptoken}& Stop tokens & \tcode{} \\ \rowsep \ref{thread.threads} & Threads & \tcode{} \\ \rowsep \ref{atomics} & Atomic operations & - \tcode{} \tcode{} \tcode{} \\ \rowsep + \tcode{}, \tcode{} \\ \rowsep \ref{thread.mutex} & Mutual exclusion & \tcode{}, \tcode{} \\ \rowsep \ref{thread.condition}& Condition variables & \tcode{} \\ \rowsep @@ -2048,260 +2048,285 @@ \begin{codeblock} namespace std { // \ref{atomics.order}, order and consistency - enum class memory_order : @\unspec@; + enum class memory_order : @\unspec@; // freestanding + inline constexpr memory_order memory_order_relaxed = memory_order::relaxed; + inline constexpr memory_order memory_order_consume = memory_order::consume; + inline constexpr memory_order memory_order_acquire = memory_order::acquire; + inline constexpr memory_order memory_order_release = memory_order::release; + inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; + inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; + template - T kill_dependency(T y) noexcept; + T kill_dependency(T y) noexcept; // freestanding } // \ref{atomics.lockfree}, lock-free property -#define ATOMIC_BOOL_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR8_T_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR16_T_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR32_T_LOCK_FREE @\unspec@ -#define ATOMIC_WCHAR_T_LOCK_FREE @\unspec@ -#define ATOMIC_SHORT_LOCK_FREE @\unspec@ -#define ATOMIC_INT_LOCK_FREE @\unspec@ -#define ATOMIC_LONG_LOCK_FREE @\unspec@ -#define ATOMIC_LLONG_LOCK_FREE @\unspec@ -#define ATOMIC_POINTER_LOCK_FREE @\unspec@ +#define ATOMIC_BOOL_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_CHAR_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_CHAR8_T_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_CHAR16_T_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_CHAR32_T_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_WCHAR_T_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_SHORT_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_INT_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_LONG_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_LLONG_LOCK_FREE @\unspecnc@ // freestanding +#define ATOMIC_POINTER_LOCK_FREE @\unspecnc@ // freestanding namespace std { // \ref{atomics.ref.generic}, class template \tcode{atomic_ref} - template struct atomic_ref; + template struct atomic_ref; // freestanding // \ref{atomics.ref.pointer}, partial specialization for pointers - template struct atomic_ref; + template struct atomic_ref; // freestanding // \ref{atomics.types.generic}, class template \tcode{atomic} - template struct atomic; + template struct atomic; // freestanding // \ref{atomics.types.pointer}, partial specialization for pointers - template struct atomic; + template struct atomic; // freestanding // \ref{atomics.nonmembers}, non-member functions template - bool atomic_is_lock_free(const volatile atomic*) noexcept; + bool atomic_is_lock_free(const volatile atomic*) noexcept; // freestanding template - bool atomic_is_lock_free(const atomic*) noexcept; + bool atomic_is_lock_free(const atomic*) noexcept; // freestanding template - void atomic_store(volatile atomic*, typename atomic::value_type) noexcept; + void atomic_store(volatile atomic*, // freestanding + typename atomic::value_type) noexcept; template - void atomic_store(atomic*, typename atomic::value_type) noexcept; + void atomic_store(atomic*, typename atomic::value_type) noexcept; // freestanding template - void atomic_store_explicit(volatile atomic*, typename atomic::value_type, + void atomic_store_explicit(volatile atomic*, // freestanding + typename atomic::value_type, memory_order) noexcept; template - void atomic_store_explicit(atomic*, typename atomic::value_type, + void atomic_store_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template - T atomic_load(const volatile atomic*) noexcept; + T atomic_load(const volatile atomic*) noexcept; // freestanding template - T atomic_load(const atomic*) noexcept; + T atomic_load(const atomic*) noexcept; // freestanding template - T atomic_load_explicit(const volatile atomic*, memory_order) noexcept; + T atomic_load_explicit(const volatile atomic*, memory_order) noexcept; // freestanding template - T atomic_load_explicit(const atomic*, memory_order) noexcept; + T atomic_load_explicit(const atomic*, memory_order) noexcept; // freestanding template - T atomic_exchange(volatile atomic*, typename atomic::value_type) noexcept; + T atomic_exchange(volatile atomic*, // freestanding + typename atomic::value_type) noexcept; template - T atomic_exchange(atomic*, typename atomic::value_type) noexcept; + T atomic_exchange(atomic*, typename atomic::value_type) noexcept; // freestanding template - T atomic_exchange_explicit(volatile atomic*, typename atomic::value_type, + T atomic_exchange_explicit(volatile atomic*, // freestanding + typename atomic::value_type, memory_order) noexcept; template - T atomic_exchange_explicit(atomic*, typename atomic::value_type, + T atomic_exchange_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template - bool atomic_compare_exchange_weak(volatile atomic*, + bool atomic_compare_exchange_weak(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template - bool atomic_compare_exchange_weak(atomic*, + bool atomic_compare_exchange_weak(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template - bool atomic_compare_exchange_strong(volatile atomic*, + bool atomic_compare_exchange_strong(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template - bool atomic_compare_exchange_strong(atomic*, + bool atomic_compare_exchange_strong(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template - bool atomic_compare_exchange_weak_explicit(volatile atomic*, + bool atomic_compare_exchange_weak_explicit(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template - bool atomic_compare_exchange_weak_explicit(atomic*, + bool atomic_compare_exchange_weak_explicit(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template - bool atomic_compare_exchange_strong_explicit(volatile atomic*, + bool atomic_compare_exchange_strong_explicit(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template - bool atomic_compare_exchange_strong_explicit(atomic*, + bool atomic_compare_exchange_strong_explicit(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template - T atomic_fetch_add(volatile atomic*, typename atomic::difference_type) noexcept; + T atomic_fetch_add(volatile atomic*, // freestanding + typename atomic::difference_type) noexcept; template - T atomic_fetch_add(atomic*, typename atomic::difference_type) noexcept; + T atomic_fetch_add(atomic*, typename atomic::difference_type) noexcept; // freestanding template - T atomic_fetch_add_explicit(volatile atomic*, typename atomic::difference_type, + T atomic_fetch_add_explicit(volatile atomic*, // freestanding + typename atomic::difference_type, memory_order) noexcept; template - T atomic_fetch_add_explicit(atomic*, typename atomic::difference_type, + T atomic_fetch_add_explicit(atomic*, typename atomic::difference_type, // freestanding memory_order) noexcept; template - T atomic_fetch_sub(volatile atomic*, typename atomic::difference_type) noexcept; + T atomic_fetch_sub(volatile atomic*, // freestanding + typename atomic::difference_type) noexcept; template - T atomic_fetch_sub(atomic*, typename atomic::difference_type) noexcept; + T atomic_fetch_sub(atomic*, typename atomic::difference_type) noexcept; // freestanding template - T atomic_fetch_sub_explicit(volatile atomic*, typename atomic::difference_type, + T atomic_fetch_sub_explicit(volatile atomic*, // freestanding + typename atomic::difference_type, memory_order) noexcept; template - T atomic_fetch_sub_explicit(atomic*, typename atomic::difference_type, + T atomic_fetch_sub_explicit(atomic*, typename atomic::difference_type, // freestanding memory_order) noexcept; template - T atomic_fetch_and(volatile atomic*, typename atomic::value_type) noexcept; + T atomic_fetch_and(volatile atomic*, // freestanding + typename atomic::value_type) noexcept; template - T atomic_fetch_and(atomic*, typename atomic::value_type) noexcept; + T atomic_fetch_and(atomic*, typename atomic::value_type) noexcept; // freestanding template - T atomic_fetch_and_explicit(volatile atomic*, typename atomic::value_type, + T atomic_fetch_and_explicit(volatile atomic*, // freestanding + typename atomic::value_type, memory_order) noexcept; template - T atomic_fetch_and_explicit(atomic*, typename atomic::value_type, + T atomic_fetch_and_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template - T atomic_fetch_or(volatile atomic*, typename atomic::value_type) noexcept; + T atomic_fetch_or(volatile atomic*, // freestanding + typename atomic::value_type) noexcept; template - T atomic_fetch_or(atomic*, typename atomic::value_type) noexcept; + T atomic_fetch_or(atomic*, typename atomic::value_type) noexcept; // freestanding template - T atomic_fetch_or_explicit(volatile atomic*, typename atomic::value_type, + T atomic_fetch_or_explicit(volatile atomic*, // freestanding + typename atomic::value_type, memory_order) noexcept; template - T atomic_fetch_or_explicit(atomic*, typename atomic::value_type, + T atomic_fetch_or_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template - T atomic_fetch_xor(volatile atomic*, typename atomic::value_type) noexcept; + T atomic_fetch_xor(volatile atomic*, // freestanding + typename atomic::value_type) noexcept; template - T atomic_fetch_xor(atomic*, typename atomic::value_type) noexcept; + T atomic_fetch_xor(atomic*, typename atomic::value_type) noexcept; // freestanding template - T atomic_fetch_xor_explicit(volatile atomic*, typename atomic::value_type, + T atomic_fetch_xor_explicit(volatile atomic*, // freestanding + typename atomic::value_type, memory_order) noexcept; template - T atomic_fetch_xor_explicit(atomic*, typename atomic::value_type, + T atomic_fetch_xor_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template - void atomic_wait(const volatile atomic*, typename atomic::value_type); + void atomic_wait(const volatile atomic*, typename atomic::value_type); // freestanding template - void atomic_wait(const atomic*, typename atomic::value_type); + void atomic_wait(const atomic*, typename atomic::value_type); // freestanding template - void atomic_wait_explicit(const volatile atomic*, typename atomic::value_type, + void atomic_wait_explicit(const volatile atomic*, // freestanding + typename atomic::value_type, memory_order); template - void atomic_wait_explicit(const atomic*, typename atomic::value_type, + void atomic_wait_explicit(const atomic*, typename atomic::value_type, // freestanding memory_order); template - void atomic_notify_one(volatile atomic*); + void atomic_notify_one(volatile atomic*); // freestanding template - void atomic_notify_one(atomic*); + void atomic_notify_one(atomic*); // freestanding template - void atomic_notify_all(volatile atomic*); + void atomic_notify_all(volatile atomic*); // freestanding template - void atomic_notify_all(atomic*); + void atomic_notify_all(atomic*); // freestanding // \ref{atomics.alias}, type aliases - using atomic_bool = atomic; - using atomic_char = atomic; - using atomic_schar = atomic; - using atomic_uchar = atomic; - using atomic_short = atomic; - using atomic_ushort = atomic; - using atomic_int = atomic; - using atomic_uint = atomic; - using atomic_long = atomic; - using atomic_ulong = atomic; - using atomic_llong = atomic; - using atomic_ullong = atomic; - using atomic_char8_t = atomic; - using atomic_char16_t = atomic; - using atomic_char32_t = atomic; - using atomic_wchar_t = atomic; - - using atomic_int8_t = atomic; - using atomic_uint8_t = atomic; - using atomic_int16_t = atomic; - using atomic_uint16_t = atomic; - using atomic_int32_t = atomic; - using atomic_uint32_t = atomic; - using atomic_int64_t = atomic; - using atomic_uint64_t = atomic; - - using atomic_int_least8_t = atomic; - using atomic_uint_least8_t = atomic; - using atomic_int_least16_t = atomic; - using atomic_uint_least16_t = atomic; - using atomic_int_least32_t = atomic; - using atomic_uint_least32_t = atomic; - using atomic_int_least64_t = atomic; - using atomic_uint_least64_t = atomic; - - using atomic_int_fast8_t = atomic; - using atomic_uint_fast8_t = atomic; - using atomic_int_fast16_t = atomic; - using atomic_uint_fast16_t = atomic; - using atomic_int_fast32_t = atomic; - using atomic_uint_fast32_t = atomic; - using atomic_int_fast64_t = atomic; - using atomic_uint_fast64_t = atomic; - - using atomic_intptr_t = atomic; - using atomic_uintptr_t = atomic; - using atomic_size_t = atomic; - using atomic_ptrdiff_t = atomic; - using atomic_intmax_t = atomic; - using atomic_uintmax_t = atomic; + using atomic_bool = atomic; // freestanding + using atomic_char = atomic; // freestanding + using atomic_schar = atomic; // freestanding + using atomic_uchar = atomic; // freestanding + using atomic_short = atomic; // freestanding + using atomic_ushort = atomic; // freestanding + using atomic_int = atomic; // freestanding + using atomic_uint = atomic; // freestanding + using atomic_long = atomic; // freestanding + using atomic_ulong = atomic; // freestanding + using atomic_llong = atomic; // freestanding + using atomic_ullong = atomic; // freestanding + using atomic_char8_t = atomic; // freestanding + using atomic_char16_t = atomic; // freestanding + using atomic_char32_t = atomic; // freestanding + using atomic_wchar_t = atomic; // freestanding + + using atomic_int8_t = atomic; // freestanding + using atomic_uint8_t = atomic; // freestanding + using atomic_int16_t = atomic; // freestanding + using atomic_uint16_t = atomic; // freestanding + using atomic_int32_t = atomic; // freestanding + using atomic_uint32_t = atomic; // freestanding + using atomic_int64_t = atomic; // freestanding + using atomic_uint64_t = atomic; // freestanding + + using atomic_int_least8_t = atomic; // freestanding + using atomic_uint_least8_t = atomic; // freestanding + using atomic_int_least16_t = atomic; // freestanding + using atomic_uint_least16_t = atomic; // freestanding + using atomic_int_least32_t = atomic; // freestanding + using atomic_uint_least32_t = atomic; // freestanding + using atomic_int_least64_t = atomic; // freestanding + using atomic_uint_least64_t = atomic; // freestanding + + using atomic_int_fast8_t = atomic; // freestanding + using atomic_uint_fast8_t = atomic; // freestanding + using atomic_int_fast16_t = atomic; // freestanding + using atomic_uint_fast16_t = atomic; // freestanding + using atomic_int_fast32_t = atomic; // freestanding + using atomic_uint_fast32_t = atomic; // freestanding + using atomic_int_fast64_t = atomic; // freestanding + using atomic_uint_fast64_t = atomic; // freestanding + + using atomic_intptr_t = atomic; // freestanding + using atomic_uintptr_t = atomic; // freestanding + using atomic_size_t = atomic; // freestanding + using atomic_ptrdiff_t = atomic; // freestanding + using atomic_intmax_t = atomic; // freestanding + using atomic_uintmax_t = atomic; // freestanding using atomic_signed_lock_free = @\seebelow@; using atomic_unsigned_lock_free = @\seebelow@; // \ref{atomics.flag}, flag type and operations - struct atomic_flag; - - bool atomic_flag_test(const volatile atomic_flag*) noexcept; - bool atomic_flag_test(const atomic_flag*) noexcept; - bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept; - bool atomic_flag_test_explicit(const atomic_flag*, memory_order) noexcept; - bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; - bool atomic_flag_test_and_set(atomic_flag*) noexcept; - bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept; - bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; - void atomic_flag_clear(volatile atomic_flag*) noexcept; - void atomic_flag_clear(atomic_flag*) noexcept; - void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; - void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; - - void atomic_flag_wait(const volatile atomic_flag*, bool) noexcept; - void atomic_flag_wait(const atomic_flag*, bool) noexcept; - void atomic_flag_wait_explicit(const volatile atomic_flag*, + struct atomic_flag; // freestanding + + bool atomic_flag_test(const volatile atomic_flag*) noexcept; // freestanding + bool atomic_flag_test(const atomic_flag*) noexcept; // freestanding + bool atomic_flag_test_explicit(const volatile atomic_flag*, // freestanding + memory_order) noexcept; + bool atomic_flag_test_explicit(const atomic_flag*, memory_order) noexcept; // freestanding + bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; // freestanding + bool atomic_flag_test_and_set(atomic_flag*) noexcept; // freestanding + bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, // freestanding + memory_order) noexcept; + bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; // freestanding + void atomic_flag_clear(volatile atomic_flag*) noexcept; // freestanding + void atomic_flag_clear(atomic_flag*) noexcept; // freestanding + void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; // freestanding + void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; // freestanding + + void atomic_flag_wait(const volatile atomic_flag*, bool) noexcept; // freestanding + void atomic_flag_wait(const atomic_flag*, bool) noexcept; // freestanding + void atomic_flag_wait_explicit(const volatile atomic_flag*, // freestanding bool, memory_order) noexcept; - void atomic_flag_wait_explicit(const atomic_flag*, + void atomic_flag_wait_explicit(const atomic_flag*, // freestanding bool, memory_order) noexcept; - void atomic_flag_notify_one(volatile atomic_flag*) noexcept; - void atomic_flag_notify_one(atomic_flag*) noexcept; - void atomic_flag_notify_all(volatile atomic_flag*) noexcept; - void atomic_flag_notify_all(atomic_flag*) noexcept; + void atomic_flag_notify_one(volatile atomic_flag*) noexcept; // freestanding + void atomic_flag_notify_one(atomic_flag*) noexcept; // freestanding + void atomic_flag_notify_all(volatile atomic_flag*) noexcept; // freestanding + void atomic_flag_notify_all(atomic_flag*) noexcept; // freestanding + #define ATOMIC_FLAG_INIT @\seebelownc@ // freestanding // \ref{atomics.fences}, fences - extern "C" void atomic_thread_fence(memory_order) noexcept; - extern "C" void atomic_signal_fence(memory_order) noexcept; + extern "C" void atomic_thread_fence(memory_order) noexcept; // freestanding + extern "C" void atomic_signal_fence(memory_order) noexcept; // freestanding } \end{codeblock} @@ -2397,12 +2422,6 @@ enum class memory_order : @\unspec@ { relaxed, consume, acquire, release, acq_rel, seq_cst }; - inline constexpr memory_order memory_order_relaxed = memory_order::relaxed; - inline constexpr memory_order memory_order_consume = memory_order::consume; - inline constexpr memory_order memory_order_acquire = memory_order::acquire; - inline constexpr memory_order memory_order_release = memory_order::release; - inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; - inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; } \end{codeblock} @@ -2637,14 +2656,11 @@ value of 2 indicates that the types are always lock-free. \pnum -At least one signed integral specialization of the \tcode{atomic} template, +On a hosted implementation\iref{compliance}, +at least one signed integral specialization of the \tcode{atomic} template, along with the specialization for the corresponding unsigned type\iref{basic.fundamental}, is always lock-free. -\begin{note} -\indextext{implementation!freestanding}% -This requirement is optional in freestanding implementations\iref{compliance}. -\end{note} \pnum The functions \tcode{atomic::is_lock_free} and @@ -3296,10 +3312,7 @@ \pnum \indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point}>}}% There are specializations of the \tcode{atomic_ref} class template -for the floating-point types -\tcode{float}, -\tcode{double}, and -\tcode{long double}. +for all cv-unqualified floating-point types. For each such type \tcode{\placeholder{floating-point}}, the specialization \tcode{atomic_ref<\placeholder{floating-\-point}>} provides additional atomic operations appropriate to floating-point types. @@ -4348,10 +4361,7 @@ \indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}}% \pnum There are specializations of the \tcode{atomic} -class template for the floating-point types -\tcode{float}, -\tcode{double}, and -\tcode{long double}. +class template for all cv-unqualified floating-point types. For each such type \tcode{\placeholdernc{floating-point}}, the specialization \tcode{atomic<\placeholder{floating-point}>} provides additional atomic operations appropriate to floating-point types. @@ -5657,6 +5667,26 @@ This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} +\indexlibraryglobal{ATOMIC_FLAG_INIT}% +\begin{itemdecl} +#define ATOMIC_FLAG_INIT @\seebelow@ +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +The macro \tcode{ATOMIC_FLAG_INIT} is defined in such a way that +it can be used to initialize an object of type \tcode{atomic_flag} +to the clear state. +The macro can be used in the form: +\begin{codeblock} +atomic_flag guard = ATOMIC_FLAG_INIT; +\end{codeblock} +It is unspecified whether the macro can be used +in other initialization contexts. +For a complete static-duration object, that initialization shall be static. +\end{itemdescr} + \rSec2[atomics.fences]{Fences} \pnum @@ -5825,14 +5855,17 @@ using std::@\libglobal{atomic_fetch_add_explicit}@; // \seebelow using std::@\libglobal{atomic_fetch_sub}@; // \seebelow using std::@\libglobal{atomic_fetch_sub_explicit}@; // \seebelow -using std::@\libglobal{atomic_fetch_or}@; // \seebelow -using std::@\libglobal{atomic_fetch_or_explicit}@; // \seebelow using std::@\libglobal{atomic_fetch_and}@; // \seebelow using std::@\libglobal{atomic_fetch_and_explicit}@; // \seebelow +using std::@\libglobal{atomic_fetch_or}@; // \seebelow +using std::@\libglobal{atomic_fetch_or_explicit}@; // \seebelow +using std::@\libglobal{atomic_fetch_xor}@; // \seebelow +using std::@\libglobal{atomic_fetch_xor_explicit}@; // \seebelow using std::@\libglobal{atomic_flag_test_and_set}@; // \seebelow using std::@\libglobal{atomic_flag_test_and_set_explicit}@; // \seebelow using std::@\libglobal{atomic_flag_clear}@; // \seebelow using std::@\libglobal{atomic_flag_clear_explicit}@; // \seebelow +#define ATOMIC_FLAG_INIT @\seebelow@ using std::@\libglobal{atomic_thread_fence}@; // \seebelow using std::@\libglobal{atomic_signal_fence}@; // \seebelow @@ -7062,7 +7095,7 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == 0} and \tcode{owns == false}. +\tcode{pm == nullptr} and \tcode{owns == false}. \end{itemdescr} \indexlibraryctor{unique_lock}% @@ -7269,11 +7302,11 @@ \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{try_lock()}. +\tcode{pm->try_lock()}. \pnum \returns -The value returned by the call to \tcode{try_lock()}. +The value returned by \tcode{pm->try_lock()}. \pnum \throws @@ -7308,15 +7341,15 @@ \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{try_lock_until(abs_time)}. +\tcode{pm->try_lock_until(abs_time)}. \pnum \returns -The value returned by the call to \tcode{try_lock_until(abs_time)}. +The value returned by \tcode{pm->try_lock_until(abs_time)}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock_until()}. \tcode{system_error} when an +Any exception thrown by \tcode{pm->try_lock_until(abstime)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum @@ -7345,15 +7378,15 @@ \pnum \ensures -\tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{try_lock_for(rel_time)}. +\tcode{owns == res}, where \tcode{res} is the value returned by \tcode{pm->try_lock_for(rel_time)}. \pnum \returns -The value returned by the call to \tcode{try_lock_for(rel_time)}. +The value returned by \tcode{pm->try_lock_for(rel_time)}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock_for()}. \tcode{system_error} when an +Any exception thrown by \tcode{pm->try_lock_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum @@ -9253,7 +9286,7 @@ \effects Repeatedly performs the following steps, in order: \begin{itemize} -\item Evaluates \tcode{try_acquire}. If the result is \tcode{true}, returns. +\item Evaluates \tcode{try_acquire()}. If the result is \tcode{true}, returns. \item \indextext{block (execution)}% Blocks on \tcode{*this} until \tcode{counter} is greater than zero. @@ -11121,7 +11154,7 @@ Once evaluation of \tcode{invoke(std::move(g), std::move(xyz))} begins, the function is no longer considered deferred. -\recommended + \recommended If this policy is specified together with other policies, such as when using a \tcode{policy} value of \tcode{launch::async | launch::deferred}, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively @@ -11318,10 +11351,20 @@ \pnum \constraints \tcode{\&F::operator()} is well-formed when -treated as an unevaluated operand\iref{term.unevaluated.operand} and -\tcode{decltype(\brk{}\&F::operator())} is of the form +treated as an unevaluated operand\iref{term.unevaluated.operand} and either +\begin{itemize} +\item +\tcode{F::operator()} is a non-static member function and +\tcode{decltype(\brk{}\&F::operator())} is either of the form \tcode{R(G::*)(A...)}~\cv{}~\tcode{\opt{\&}~\opt{noexcept}} -for a class type \tcode{G}. +or of the form +\tcode{R(*)(G, A...)~\opt{noexcept}} +for a type \tcode{G}, or +\item +\tcode{F::operator()} is a static member function and +\tcode{decltype(\&F::operator())} is of the form +\tcode{R(*)(A...) \opt{noexcept}}. +\end{itemize} \pnum \remarks diff --git a/source/time.tex b/source/time.tex index 667d1fc334..2263d4b7cc 100644 --- a/source/time.tex +++ b/source/time.tex @@ -2145,7 +2145,7 @@ In the list above, the use of \tcode{\placeholder{num}} and \tcode{\placeholder{den}} -refer to the static data members of \tcode{Period::type}, +refers to the static data members of \tcode{Period::type}, which are converted to arrays of \tcode{charT} using a decimal conversion with no leading zeroes. \pnum @@ -4681,7 +4681,7 @@ \indexlibrarymember{operator-}{year}% \begin{itemdecl} -constexpr year year::operator-() const noexcept; +constexpr year operator-() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -10509,6 +10509,11 @@ the formats specified in ISO 8601:2004 shall be used where so described. Some of the conversion specifiers depend on the formatting locale. +If the string literal encoding is a Unicode encoding form and +the locale is among +an \impldef{locales with Unicode support for chrono types} set of locales, +each replacement that depends on the locale is performed as if +the replacement character sequence is converted to the string literal encoding. If the formatted object does not contain the information the conversion specifier refers to, an exception of type \tcode{format_error} is thrown. diff --git a/source/utilities.tex b/source/utilities.tex index b85cbf93e1..df39cb6a9b 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -35,6 +35,7 @@ throughout the rest of the library. \begin{codeblock} +// all freestanding #include // see \ref{compare.syn} #include // see \ref{initializer.list.syn} @@ -54,6 +55,8 @@ constexpr T&& forward(remove_reference_t& t) noexcept; template constexpr T&& forward(remove_reference_t&& t) noexcept; + template + [[nodiscard]] constexpr auto forward_like(U&& x) noexcept -> @\seebelow@; template constexpr remove_reference_t&& move(T&&) noexcept; template @@ -357,6 +360,57 @@ \end{example} \end{itemdescr} +\indexlibraryglobal{forward_like}% +\begin{itemdecl} +template + [[nodiscard]] constexpr auto forward_like(U&& x) noexcept -> @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{itemize} +\item +Let \tcode{\exposid{COPY_CONST}(A, B)} be \tcode{const B} +if \tcode{A} is a const type, otherwise \tcode{B}. +\item +Let \tcode{\exposid{OVERRIDE_REF}(A, B)} be \tcode{remove_reference_t\&\&} +if \tcode{A} is an rvalue reference type, otherwise \tcode{B\&}. +\item +Let \tcode{V} be +\begin{codeblock} +@\exposid{OVERRIDE_REF}@(T&&, @\exposid{COPY_CONST}@(remove_reference_t, remove_reference_t)) +\end{codeblock} +\end{itemize} + +\pnum +\returns +\tcode{static_cast(x)}. + +\pnum +\remarks +The return type is \tcode{V}. + +\pnum +\begin{example} +\begin{codeblock} +struct accessor { + vector* container; + decltype(auto) operator[](this auto&& self, size_t i) { + return std::forward_like((*container)[i]); + } +}; +void g() { + vector v{"a"s, "b"s}; + accessor a{&v}; + string& x = a[0]; // OK, binds to lvalue reference + string&& y = std::move(a)[0]; // OK, is rvalue reference + string const&& z = std::move(as_const(a))[1]; // OK, is \tcode{const\&\&} + string& w = as_const(a)[1]; // error: will not bind to non-const +} +\end{codeblock} +\end{example} +\end{itemdescr} + \indexlibrary{\idxcode{move}!function}% \indextext{\idxcode{move}}% \begin{itemdecl} @@ -683,6 +737,8 @@ constexpr explicit(@\seebelow@) pair(pair&& p); template constexpr explicit(@\seebelow@) pair(const pair&& p); + template<@\exposconcept{pair-like}@ P> + constexpr explicit(@\seebelow@) pair(P&& p); template constexpr pair(piecewise_construct_t, tuple first_args, tuple second_args); @@ -699,6 +755,10 @@ constexpr pair& operator=(pair&& p); template constexpr const pair& operator=(pair&& p) const; + template<@\exposconcept{pair-like}@ P> + constexpr pair& operator=(P&& p); + template<@\exposconcept{pair-like}@ P> + constexpr const pair& operator=(P&& p) const; constexpr void swap(pair& p) noexcept(@\seebelow@); constexpr void swap(const pair& p) const noexcept(@\seebelow@); @@ -824,6 +884,7 @@ template constexpr explicit(@\seebelow@) pair(const pair& p); template constexpr explicit(@\seebelow@) pair(pair&& p); template constexpr explicit(@\seebelow@) pair(const pair&& p); +template<@\exposconcept{pair-like}@ P> constexpr explicit(@\seebelow@) pair(P&& p); \end{itemdecl} \begin{itemdescr} @@ -1062,6 +1123,70 @@ \tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator=}{pair}% +\begin{itemdecl} +template<@\exposconcept{pair-like}@ P> constexpr pair& operator=(P&& p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{\exposconcept{different-from}}\iref{range.utility.helpers} +is \tcode{true}, +\item +\tcode{remove_cvref_t

} is not a specialization of \tcode{ranges::subrange}, +\item +\tcode{is_assignable_v(std::forward

(p)))>} +is \tcode{true}, and +\item +\tcode{is_assignable_v(std::forward

(p)))>} +is \tcode{true}. +\end{itemize} + +\pnum +\effects +Assigns \tcode{get<0>(std::forward

(p))} to \tcode{first} and +\tcode{get<1>(std::forward

(p))} to \tcode{sec\-ond}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{pair}% +\begin{itemdecl} +template<@\exposconcept{pair-like}@ P> constexpr const pair& operator=(P&& p) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{\exposconcept{different-from}}\iref{range.utility.helpers} +is \tcode{true}, +\item +\tcode{remove_cvref_t

} is not a specialization of \tcode{ranges::subrange}, +\item +\tcode{is_assignable_v(std::forward

(p)))>} +is \tcode{true}, and +\item +\tcode{is_assignable_v(std::forward

(p)))>} +is \tcode{true}. +\end{itemize} + +\pnum +\effects +Assigns \tcode{get<0>(std::forward

(p))} to \tcode{first} and +\tcode{get<1>(std::forward

(p))} to \tcode{sec\-ond}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + \indexlibrarymember{operator=}{pair}% \begin{itemdecl} template constexpr const pair& operator=(pair&& p) const; @@ -1350,6 +1475,7 @@ \indexheader{tuple}% \begin{codeblock} +// all freestanding #include // see \ref{compare.syn} namespace std { @@ -1357,18 +1483,19 @@ template class tuple; - template class TQual, - template class UQual> - requires requires { typename tuple, UQual>...>; } - struct basic_common_reference, tuple, TQual, UQual> { - using type = tuple, UQual>...>; - }; + // \ref{tuple.like}, concept \exposconcept{tuple-like} + template + concept @\exposconcept{tuple-like}@ = @\seebelownc@; // \expos + template + concept @\defexposconcept{pair-like}@ = // \expos + @\exposconcept{tuple-like}@ && tuple_size_v> == 2; - template - requires requires { typename tuple...>; } - struct common_type, tuple> { - using type = tuple...>; - }; + // \ref{tuple.common.ref}, \tcode{common_reference} related specializations + template<@\exposconceptnc{tuple-like}@ TTuple, @\exposconceptnc{tuple-like}@ UTuple, + template class TQual, template class UQual> + struct basic_common_reference; + template<@\exposconceptnc{tuple-like}@ TTuple, @\exposconceptnc{tuple-like}@ UTuple> + struct common_type; // \ref{tuple.creation}, tuple creation functions inline constexpr @\unspec@ ignore; @@ -1382,14 +1509,14 @@ template constexpr tuple tie(TTypes&...) noexcept; - template + template<@\exposconceptnc{tuple-like}@... Tuples> constexpr tuple tuple_cat(Tuples&&...); // \ref{tuple.apply}, calling a function with a tuple of arguments - template - constexpr decltype(auto) apply(F&& f, Tuple&& t); + template + constexpr decltype(auto) apply(F&& f, Tuple&& t) noexcept(@\seebelow@); - template + template constexpr T make_from_tuple(Tuple&& t); // \ref{tuple.helper}, tuple helper classes @@ -1428,9 +1555,13 @@ // \ref{tuple.rel}, relational operators template constexpr bool operator==(const tuple&, const tuple&); + template + constexpr bool operator==(const tuple&, const UTuple&); template - constexpr common_comparison_category_t<@\placeholder{synth-three-way-result}@...> + constexpr common_comparison_category_t<@\placeholdernc{synth-three-way-result}@...> operator<=>(const tuple&, const tuple&); + template + constexpr @\seebelownc@ operator<=>(const tuple&, const UTuple&); // \ref{tuple.traits}, allocator-related traits template @@ -1448,6 +1579,21 @@ } \end{codeblock} +\rSec2[tuple.like]{Concept \ecname{tuple-like}} + +\begin{itemdecl} +template + concept @\defexposconcept{tuple-like}@ = @\seebelownc@; // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +A type \tcode{T} models and satisfies +the exposition-only concept \exposconcept{tuple-like} +if \tcode{remove_cvref_t} is a specialization of +\tcode{array}, \tcode{pair}, \tcode{tuple}, or \tcode{ranges::subrange}. +\end{itemdescr} + \rSec2[tuple.tuple]{Class template \tcode{tuple}} \indexlibraryglobal{tuple}% @@ -1483,6 +1629,9 @@ template constexpr explicit(@\seebelow@) tuple(const pair&&); // only if \tcode{sizeof...(Types) == 2} + template<@\exposconcept{tuple-like}@ UTuple> + constexpr explicit(@\seebelow@) tuple(UTuple&&); + // allocator-extended constructors template constexpr explicit(@\seebelow@) @@ -1522,6 +1671,9 @@ constexpr explicit(@\seebelow@) tuple(allocator_arg_t, const Alloc& a, const pair&&); + template + constexpr explicit(@\seebelow@) tuple(allocator_arg_t, const Alloc& a, UTuple&&); + // \ref{tuple.assign}, \tcode{tuple} assignment constexpr tuple& operator=(const tuple&); constexpr const tuple& operator=(const tuple&) const; @@ -1547,6 +1699,11 @@ template constexpr const tuple& operator=(pair&&) const; // only if \tcode{sizeof...(Types) == 2} + template<@\exposconceptnc{tuple-like}@ UTuple> + constexpr tuple& operator=(UTuple&&); + template<@\exposconceptnc{tuple-like}@ UTuple> + constexpr const tuple& operator=(UTuple&&) const; + // \ref{tuple.swap}, \tcode{tuple} swap constexpr void swap(tuple&) noexcept(@\seebelow@); constexpr void swap(const tuple&) const noexcept(@\seebelow@); @@ -1689,7 +1846,7 @@ \end{codeblock} This constructor is defined as deleted if \begin{codeblock} -(reference_constructs_from_temporary_v || ...) +(reference_constructs_from_temporary_v || ...) \end{codeblock} is \tcode{true}. \end{itemdescr} @@ -1817,6 +1974,56 @@ is \tcode{true}. \end{itemdescr} +\indexlibraryctor{tuple}% +\begin{itemdecl} +template<@\exposconcept{tuple-like}@ UTuple> + constexpr explicit(@\seebelow@) tuple(UTuple&& u); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{I} be the pack \tcode{0, 1, \ldots, (sizeof...(Types) - 1)}. + +\pnum +\constraints +\begin{itemize} +\item +\tcode{\exposconcept{different-from}}\iref{range.utility.helpers} +is \tcode{true}, + +\item +\tcode{remove_cvref_t} +is not a specialization of \tcode{ranges::subrange}, + +\item +\tcode{sizeof...(Types)} +equals \tcode{tuple_size_v>}, + +\item +\tcode{(is_constructible_v(std::forward(u)))> \&\& ...)} +is\linebreak{} % Overfull +\tcode{true}, and + +\item +either \tcode{sizeof...(Types)} is not \tcode{1}, or +(when \tcode{Types...} expands to \tcode{T}) +\tcode{is_convertible_v} and +\tcode{is_constructible_v} are both \tcode{false}. +\end{itemize} + +\pnum +\effects +For all $i$, initializes the $i^\text{th}$ element of \tcode{*this} with +\tcode{get<$i$>(std::forward(u))}. + +\pnum +\remarks +The expression inside \tcode{explicit} is equivalent to: +\begin{codeblock} +!(is_convertible_v(std::forward(u))), Types> && ...) +\end{codeblock} +\end{itemdescr} + \indexlibraryctor{tuple}% \begin{itemdecl} template @@ -1856,6 +2063,9 @@ template constexpr explicit(@\seebelow@) tuple(allocator_arg_t, const Alloc& a, const pair&&); +template + constexpr explicit(@\seebelow@) + tuple(allocator_arg_t, const Alloc& a, UTuple&&); \end{itemdecl} \begin{itemdescr} @@ -1941,7 +2151,7 @@ \pnum \remarks -The exception specification is equivalent to the logical \logop{AND} of the +The exception specification is equivalent to the logical \logop{and} of the following expressions: \begin{codeblock} @@ -2170,6 +2380,80 @@ \tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator=}{tuple}% +\begin{itemdecl} +template<@\exposconcept{tuple-like}@ UTuple> + constexpr tuple& operator=(UTuple&& u); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{\exposconcept{different-from}}\iref{range.utility.helpers} +is \tcode{true}, + +\item +\tcode{remove_cvref_t} +is not a specialization of \tcode{ranges::subrange}, + +\item +\tcode{sizeof...(Types)} +equals \tcode{tuple_size_v>}, and, + +\item +\tcode{is_assignable_v<$\tcode{T}_i$\&, decltype(get<$i$>(std::forward(u)))>} +is \tcode{true} for all $i$. +\end{itemize} + +\pnum +\effects +For all $i$, assigns \tcode{get<$i$>(std::forward(u))} +to \tcode{get<$i$>(*this)}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{tuple}% +\begin{itemdecl} +template<@\exposconcept{tuple-like}@ UTuple> + constexpr const tuple& operator=(UTuple&& u) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{\exposconcept{different-from}}\iref{range.utility.helpers} +is \tcode{true}, + +\item +\tcode{remove_cvref_t} +is not a specialization of \tcode{ranges::subrange}, + +\item +\tcode{sizeof...(Types)} +equals \tcode{tuple_size_v>}, and, + +\item +\tcode{is_assignable_v(std::forward(u)))>} +is \tcode{true} for all $i$. +\end{itemize} + +\pnum +\effects +For all $i$, assigns +\tcode{get<$i$>(std::forward(u))} to \tcode{get<$i$>(*this)}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + \rSec3[tuple.swap]{\tcode{swap}} \indexlibrarymember{swap}{tuple}% @@ -2233,7 +2517,7 @@ \begin{example} \begin{codeblock} int i; float j; -make_tuple(1, ref(i), cref(j)) +make_tuple(1, ref(i), cref(j)); \end{codeblock} creates a tuple of type \tcode{tuple}. \end{example} @@ -2290,63 +2574,55 @@ \indexlibraryglobal{tuple_cat} \begin{itemdecl} -template +template<@\exposconcept{tuple-like}@... Tuples> constexpr tuple tuple_cat(Tuples&&... tpls); \end{itemdecl} -\begin{itemdescr} % NOCHECK: order -\pnum -In the following paragraphs, let $\tcode{T}_i$ be the $i^\text{th}$ type in \tcode{Tuples}, -$\tcode{U}_i$ be \tcode{remove_reference_t}, and $\tcode{tp}_i$ be the $i^\text{th}$ -parameter in the function parameter pack \tcode{tpls}, where all indexing is -zero-based. - +\begin{itemdescr} \pnum -\expects -For all $i$, $\tcode{U}_i$ is the type -$\cv_i$ \tcode{tuple<$\tcode{Args}_i$...>}, where $\cv_i$ is the (possibly empty) $i^\text{th}$ -\grammarterm{cv-qualifier-seq} and $\tcode{Args}_i$ is the template parameter pack representing the element -types in $\tcode{U}_i$. Let $\tcode{A}_{ik}$ be the ${k}^\text{th}$ type in $\tcode{Args}_i$. For all -$\tcode{A}_{ik}$ the following requirements are met: +Let $n$ be \tcode{sizeof...(Tuples)}. +For every integer $0 \leq i < n$: \begin{itemize} -\item If $\tcode{T}_i$ is deduced as an lvalue reference type, then - \tcode{is_constructible_v<$\tcode{A}_{ik}$, $\cv{}_i\;\tcode{A}_{ik}$\&> == true}, otherwise -\item \tcode{is_constructible_v<$\tcode{A}_{ik}$, $\cv{}_i\;\tcode{A}_{ik}$\&\&> == true}. +\item +Let $\tcode{T}_i$ be the $i^\text{th}$ type in \tcode{Tuples}. +\item +Let $\tcode{U}_i$ be \tcode{remove_cvref_t<$\tcode{T}_i$>}. +\item +Let $\tcode{tp}_i$ be the $i^\text{th}$ element +in the function parameter pack \tcode{tpls}. +\item +Let $S_i$ be \tcode{tuple_size_v<$\tcode{U}_i$>}. +\item +Let $E_i^k$ be \tcode{tuple_element_t<$k$, $\tcode{U}_i$>}. +\item +Let $e_i^k$ be \tcode{get<$k$>(std::forward<$\tcode{T}_i$>($\tcode{tp}_i$))}. +\item +Let $Elems_i$ be a pack of the types $E_i^0, \dotsc, E_i^{S_{i-1}}$. +\item +Let $elems_i$ be a pack of the expressions $e_i^0, \dotsc, e_i^{S_{i-1}}$. \end{itemize} +The types in \tcode{CTypes} are equal to the ordered sequence of +the expanded packs of types +\tcode{$Elems_0$...}, \tcode{$Elems_1$...}, \ldots, \tcode{$Elems_{n-1}$...}. +Let \tcode{celems} be the ordered sequence of +the expanded packs of expressions +\tcode{$elems_0$...}, \ldots, \tcode{$elems_{n-1}$...}. \pnum -\remarks -The types in \tcode{CTypes} are equal to the ordered -sequence of the extended types -\tcode{$\tcode{Args}_0$..., $\tcode{Args}_1$..., $\dotsc$, $\tcode{Args}_{n-1}$...}, -where $n$ is -equal to \tcode{sizeof...(Tuples)}. Let \tcode{$\tcode{e}_i$...} be the $i^\text{th}$ -ordered sequence of tuple elements of the resulting \tcode{tuple} object -corresponding to the type sequence $\tcode{Args}_i$. +\mandates +\tcode{(is_constructible_v \&\& ...)} is \tcode{true}. \pnum \returns -A \tcode{tuple} object constructed by initializing the ${k_i}^\text{th}$ -type element $\tcode{e}_{ik}$ in \tcode{$\tcode{e}_i$...} with -\begin{codeblock} -get<@$k_i$@>(std::forward<@$\tcode{T}_i$@>(@$\tcode{tp}_i$@)) -\end{codeblock} -for each valid $k_i$ and each group $\tcode{e}_i$ in order. - -\pnum -\begin{note} -An implementation can support additional types in the template parameter -pack \tcode{Tuples} that support the \tcode{tuple}-like protocol, such as -\tcode{pair} and \tcode{array}. -\end{note} +\tcode{tuple(celems...)}. \end{itemdescr} \rSec2[tuple.apply]{Calling a function with a \tcode{tuple} of arguments} \indexlibraryglobal{apply}% \begin{itemdecl} -template - constexpr decltype(auto) apply(F&& f, Tuple&& t); +template + constexpr decltype(auto) apply(F&& f, Tuple&& t) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -2355,7 +2631,7 @@ Given the exposition-only function: \begin{codeblock} namespace std { - template + template constexpr decltype(auto) @\placeholdernc{apply-impl}@(F&& f, Tuple&& t, index_sequence) { // \expos return @\placeholdernc{INVOKE}@(std::forward(f), get(std::forward(t))...); // see \ref{func.require} @@ -2367,11 +2643,20 @@ return @\placeholdernc{apply-impl}@(std::forward(f), std::forward(t), make_index_sequence>>{}); \end{codeblock} + +\pnum +\remarks +Let \tcode{I} be the pack +\tcode{0, 1, ..., (tuple_size_v> - 1)}. +The exception specification is equivalent to: +\begin{codeblock} +noexcept(invoke(std::forward(f), get(std::forward(t))...)) +\end{codeblock} \end{itemdescr} \indexlibraryglobal{make_from_tuple}% \begin{itemdecl} -template +template constexpr T make_from_tuple(Tuple&& t); \end{itemdecl} @@ -2388,7 +2673,7 @@ Given the exposition-only function: \begin{codeblock} namespace std { - template + template requires is_constructible_v(declval()))...> constexpr T @\placeholdernc{make-from-tuple-impl}@(Tuple&& t, index_sequence) { // \expos return T(get(std::forward(t))...); @@ -2606,9 +2891,14 @@ \begin{itemdecl} template constexpr bool operator==(const tuple& t, const tuple& u); +template + constexpr bool operator==(const tuple& t, const UTuple& u); \end{itemdecl} \begin{itemdescr} +\pnum +For the first overload let \tcode{UTuple} be \tcode{tuple}. + \pnum \mandates For all \tcode{i}, @@ -2616,20 +2906,27 @@ \tcode{get(t) == get(u)} is a valid expression returning a type that is convertible to \tcode{bool}. \tcode{sizeof...(TTypes)} equals -\tcode{sizeof...(UTypes)}. +\tcode{tuple_size_v}. \pnum \returns \tcode{true} if \tcode{get(t) == get(u)} for all \tcode{i}, otherwise \tcode{false}. -For any two zero-length tuples \tcode{e} and \tcode{f}, \tcode{e == f} returns \tcode{true}. +\begin{note} +If \tcode{sizeof...(TTypes)} equals zero, returns \tcode{true}. +\end{note} \pnum \remarks +\begin{itemize} +\item The elementary comparisons are performed in order from the zeroth index upwards. No comparisons or element accesses are performed after the first equality comparison that evaluates to \tcode{false}. +\item +The second overload is to be found via argument-dependent lookup\iref{basic.lookup.argdep} only. +\end{itemize} \end{itemdescr} \indexlibrarymember{operator<=>}{tuple}% @@ -2637,21 +2934,34 @@ template constexpr common_comparison_category_t<@\placeholder{synth-three-way-result}@...> operator<=>(const tuple& t, const tuple& u); +template + constexpr common_comparison_category_t<@\placeholder{synth-three-way-result}@...> + operator<=>(const tuple& t, const UTuple& u); \end{itemdecl} \begin{itemdescr} +\pnum +For the second overload, \tcode{Elems} denotes the pack of types +\tcode{tuple_element_t<0, UTuple>}, +\tcode{tuple_element_t<1, UTuple>}, \ldots, +\tcode{tuple_element_t - 1, UTuple>}. + \pnum \effects Performs a lexicographical comparison between \tcode{t} and \tcode{u}. -For any two zero-length tuples \tcode{t} and \tcode{u}, -\tcode{t <=> u} returns \tcode{strong_ordering::equal}. +If \tcode{sizeof...(TTypes)} equals zero, +returns \tcode{strong_ordering::equal}. Otherwise, equivalent to: \begin{codeblock} if (auto c = @\placeholder{synth-three-way}@(get<0>(t), get<0>(u)); c != 0) return c; return @$\tcode{t}_\mathrm{tail}$@ <=> @$\tcode{u}_\mathrm{tail}$@; \end{codeblock} -where $\tcode{r}_\mathrm{tail}$ for some tuple \tcode{r} +where $\tcode{r}_\mathrm{tail}$ for some \tcode{r} is a tuple containing all but the first element of \tcode{r}. + +\pnum +\remarks +The second overload is to be found via argument-dependent lookup\iref{basic.lookup.argdep} only. \end{itemdescr} \pnum @@ -2664,23 +2974,97 @@ result of the comparison. \end{note} -\rSec2[tuple.traits]{Tuple traits} +\rSec2[tuple.common.ref]{\tcode{common_reference} related specializations} -\indexlibraryglobal{uses_allocator}% +\pnum +In the descriptions that follow: +\begin{itemize} +\item +Let \tcode{TTypes} be a pack formed by +the sequence of \tcode{tuple_element_t<$i$, TTuple>} +for every integer $0 \leq i < \tcode{tuple_size_v}$. + +\item +Let \tcode{UTypes} be a pack formed by +the sequence of \tcode{tuple_element_t<$i$, UTuple>} +for every integer $0 \leq i < \tcode{tuple_size_v}$. +\end{itemize} + +\indexlibrarymember{basic_common_reference}{tuple}% \begin{itemdecl} -template - struct uses_allocator, Alloc> : true_type { }; +template<@\exposconcept{tuple-like}@ TTuple, @\exposconcept{tuple-like}@ UTuple, + template class TQual, template class UQual> +struct basic_common_reference { + using type = @\seebelow@; +}; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{Alloc} meets -the \oldconcept{Allocator} requirements\iref{allocator.requirements.general}. +\constraints +\begin{itemize} +\item +\tcode{TTuple} is a specialization of \tcode{tuple} or +\tcode{UTuple} is a specialization of \tcode{tuple}. +\item +\tcode{is_same_v>} is \tcode{true}. +\item +\tcode{is_same_v>} is \tcode{true}. +\item +\tcode{tuple_size_v} equals \tcode{tuple_size_v}. +\item +\tcode{tuple, UQual>...>} +denotes a type. +\end{itemize} +The member \grammarterm{typedef-name} \tcode{type} denotes the type +\tcode{tuple, \linebreak{}UQual>...>}. +\end{itemdescr} -\pnum -\begin{note} -Specialization of this trait informs other library components that +\indexlibrarymember{common_type}{tuple}% +\begin{itemdecl} +template<@\exposconcept{tuple-like}@ TTuple, @\exposconcept{tuple-like}@ UTuple> +struct common_type { + using type = @\seebelow@; +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{TTuple} is a specialization of \tcode{tuple} or +\tcode{UTuple} is a specialization of \tcode{tuple}. +\item +\tcode{is_same_v>} is \tcode{true}. +\item +\tcode{is_same_v>} is \tcode{true}. +\item +\tcode{tuple_size_v} equals \tcode{tuple_size_v}. +\item +\tcode{tuple...>} denotes a type. +\end{itemize} +The member \grammarterm{typedef-name} \tcode{type} denotes the type +\tcode{tuple...>}. +\end{itemdescr} + +\rSec2[tuple.traits]{Tuple traits} + +\indexlibraryglobal{uses_allocator}% +\begin{itemdecl} +template + struct uses_allocator, Alloc> : true_type { }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{Alloc} meets +the \oldconcept{Allocator} requirements\iref{allocator.requirements.general}. + +\pnum +\begin{note} +Specialization of this trait informs other library components that \tcode{tuple} can be constructed with an allocator, even though it does not have a nested \tcode{allocator_type}. \end{note} @@ -2905,13 +3289,13 @@ it means that an object of type \tcode{T}, referred to as the optional object's \defnx{contained value}{contained value!\idxcode{optional}}, is allocated within the storage of the optional object. Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value. -The contained value shall be allocated in a region of the \tcode{optional} storage suitably aligned for the type \tcode{T}. When an object of type \tcode{optional} is contextually converted to \tcode{bool}, the conversion returns \tcode{true} if the object contains a value; otherwise the conversion returns \tcode{false}. \pnum -Member \tcode{val} is provided for exposition only. When an \tcode{optional} object contains a value, \tcode{val} points to the contained value. +When an \tcode{optional} object contains a value, +member \tcode{val} points to the contained value. \pnum \tcode{T} shall be a type @@ -4635,8 +5019,6 @@ \tcode{variant} object. Implementations are not permitted to use additional storage, such as dynamic memory, to allocate the contained value. -The contained value shall be allocated in a region of the \tcode{variant} -storage suitably aligned for all types in \tcode{Types}. \pnum All types in \tcode{Types} shall meet @@ -4734,7 +5116,7 @@ \pnum \remarks -The exception specification is equivalent to the logical \logop{AND} of +The exception specification is equivalent to the logical \logop{and} of \tcode{is_nothrow_move_con\-structible_v<$\tcode{T}_i$>} for all $i$. If \tcode{is_trivially_move_constructible_v<$\tcode{T}_i$>} is \tcode{true} for all $i$, this constructor is trivial. @@ -5347,7 +5729,7 @@ If an exception is thrown during the exchange of the values of \tcode{*this} and \tcode{rhs}, the states of the values of \tcode{*this} and of \tcode{rhs} are determined by the exception safety guarantee of \tcode{variant}'s move constructor. -The exception specification is equivalent to the logical \logop{AND} of +The exception specification is equivalent to the logical \logop{and} of \tcode{is_nothrow_move_constructible_v<$\tcode{T}_i$> \&\& is_nothrow_swappable_v<$\tcode{T}_i$>} for all $i$. \end{itemdescr} @@ -6498,7 +6880,7 @@ \indexlibraryglobal{unexpect}% \begin{codeblock} namespace std { - // \ref{expected.un.object}, class template \tcode{unexpected} + // \ref{expected.unexpected}, class template \tcode{unexpected} template class unexpected; // \ref{expected.bad}, class template \tcode{bad_expected_access} @@ -6521,7 +6903,7 @@ } \end{codeblock} -\rSec2[expected.unexpected]{Unexpected objects} +\rSec2[expected.unexpected]{Class template \tcode{unexpected}} \rSec3[expected.un.general]{General} @@ -6529,10 +6911,6 @@ Subclause \ref{expected.unexpected} describes the class template \tcode{unexpected} that represents unexpected objects stored in \tcode{expected} objects. -\rSec3[expected.un.object]{Class template \tcode{unexpected}} - -\rSec4[expected.un.object.general]{General} - \indexlibraryglobal{unexpected}% \begin{codeblock} namespace std { @@ -6541,20 +6919,20 @@ public: constexpr unexpected(const unexpected&) = default; constexpr unexpected(unexpected&&) = default; + template + constexpr explicit unexpected(Err&&); template constexpr explicit unexpected(in_place_t, Args&&...); template constexpr explicit unexpected(in_place_t, initializer_list, Args&&...); - template - constexpr explicit unexpected(Err&&); constexpr unexpected& operator=(const unexpected&) = default; constexpr unexpected& operator=(unexpected&&) = default; - constexpr const E& value() const & noexcept; - constexpr E& value() & noexcept; - constexpr const E&& value() const && noexcept; - constexpr E&& value() && noexcept; + constexpr const E& error() const & noexcept; + constexpr E& error() & noexcept; + constexpr const E&& error() const && noexcept; + constexpr E&& error() && noexcept; constexpr void swap(unexpected& other) noexcept(@\seebelow@); @@ -6564,7 +6942,7 @@ friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))); private: - E @\exposid{val}@; // \expos + E @\exposidnc{unex}@; // \expos }; template unexpected(E) -> unexpected; @@ -6579,7 +6957,7 @@ a cv-qualified type is ill-formed. -\rSec4[expected.un.ctor]{Constructors} +\rSec3[expected.un.ctor]{Constructors} \indexlibraryctor{unexpected}% \begin{itemdecl} @@ -6601,11 +6979,11 @@ \pnum \effects -Direct-non-list-initializes \exposid{val} with \tcode{std::forward(e)}. +Direct-non-list-initializes \exposid{unex} with \tcode{std::forward(e)}. \pnum \throws -Any exception thrown by the initialization of \exposid{val}. +Any exception thrown by the initialization of \exposid{unex}. \end{itemdescr} \indexlibraryctor{unexpected}% @@ -6622,11 +7000,11 @@ \pnum \effects Direct-non-list-initializes -\exposid{val} with \tcode{std::forward(args)...}. +\exposid{unex} with \tcode{std::forward(args)...}. \pnum \throws -Any exception thrown by the initialization of \exposid{val}. +Any exception thrown by the initialization of \exposid{unex}. \end{itemdescr} \indexlibraryctor{unexpected}% @@ -6643,40 +7021,40 @@ \pnum \effects Direct-non-list-initializes -\exposid{val} with \tcode{il, std::forward(args)...}. +\exposid{unex} with \tcode{il, std::forward(args)...}. \pnum \throws -Any exception thrown by the initialization of \exposid{val}. +Any exception thrown by the initialization of \exposid{unex}. \end{itemdescr} -\rSec4[expected.un.obs]{Observers} +\rSec3[expected.un.obs]{Observers} -\indexlibrarymember{value}{unexpected}% +\indexlibrarymember{error}{unexpected}% \begin{itemdecl} -constexpr const E& value() const & noexcept; -constexpr E& value() & noexcept; +constexpr const E& error() const & noexcept; +constexpr E& error() & noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\exposid{val}. +\exposid{unex}. \end{itemdescr} -\indexlibrarymember{value}{unexpected}% +\indexlibrarymember{error}{unexpected}% \begin{itemdecl} -constexpr E&& value() && noexcept; -constexpr const E&& value() const && noexcept; +constexpr E&& error() && noexcept; +constexpr const E&& error() const && noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{std::move(\exposid{val})}. +\tcode{std::move(\exposid{unex})}. \end{itemdescr} -\rSec4[expected.un.swap]{Swap} +\rSec3[expected.un.swap]{Swap} \indexlibrarymember{swap}{unexpected}% \begin{itemdecl} @@ -6691,7 +7069,7 @@ \pnum \effects Equivalent to: -\tcode{using std::swap; swap(\exposid{val}, other.\exposid{val});} +\tcode{using std::swap; swap(\exposid{unex}, other.\exposid{unex});} \end{itemdescr} \begin{itemdecl} @@ -6708,7 +7086,7 @@ Equivalent to \tcode{x.swap(y)}. \end{itemdescr} -\rSec4[expected.un.eq]{Equality operator} +\rSec3[expected.un.eq]{Equality operator} \indexlibrarymember{operator==}{unexpected}% \begin{itemdecl} @@ -6719,12 +7097,12 @@ \begin{itemdescr} \pnum \mandates -The expression \tcode{x.value() == y.value()} is well-formed and +The expression \tcode{x.error() == y.error()} is well-formed and its result is convertible to \tcode{bool}. \pnum \returns -\tcode{x.value() == y.value()}. +\tcode{x.error() == y.error()}. \end{itemdescr} \rSec2[expected.bad]{Class template \tcode{bad_expected_access}} @@ -6742,7 +7120,7 @@ E&& error() && noexcept; const E&& error() const && noexcept; private: - E @\exposid{val}@; // \expos + E @\exposidnc{unex}@; // \expos }; } \end{codeblock} @@ -6761,7 +7139,7 @@ \begin{itemdescr} \pnum \effects -Initializes \exposid{val} with \tcode{std::move(e)}. +Initializes \exposid{unex} with \tcode{std::move(e)}. \end{itemdescr} \indexlibrarymember{error}{bad_expected_access}% @@ -6773,7 +7151,7 @@ \begin{itemdescr} \pnum \returns -\exposid{val}. +\exposid{unex}. \end{itemdescr} \indexlibrarymember{error}{bad_expected_access}% @@ -6785,7 +7163,7 @@ \begin{itemdescr} \pnum \returns -\tcode{std::move(\exposid{val})}. +\tcode{std::move(\exposid{unex})}. \end{itemdescr} \indexlibrarymember{what}{bad_expected_access}% @@ -6847,8 +7225,8 @@ // \ref{expected.object.ctor}, constructors constexpr expected(); - constexpr explicit(@\seebelow@) expected(const expected&); - constexpr explicit(@\seebelow@) expected(expected&&) noexcept(@\seebelow@); + constexpr expected(const expected&); + constexpr expected(expected&&) noexcept(@\seebelow@); template constexpr explicit(@\seebelow@) expected(const expected&); template @@ -6905,10 +7283,10 @@ constexpr T& value() &; constexpr const T&& value() const &&; constexpr T&& value() &&; - constexpr const E& error() const &; - constexpr E& error() &; - constexpr const E&& error() const &&; - constexpr E&& error() &&; + constexpr const E& error() const & noexcept; + constexpr E& error() & noexcept; + constexpr const E&& error() const && noexcept; + constexpr E&& error() && noexcept; template constexpr T value_or(U&&) const &; template constexpr T value_or(U&&) &&; @@ -6936,12 +7314,8 @@ a value of type \tcode{E} within its own storage. Implementations are not permitted to use additional storage, such as dynamic memory, -to allocate the object of type \tcode{T} or the object of type E. -These objects are allocated in a region of the \tcode{expected} storage -suitably aligned for the types \tcode{T} and \tcode{E}. -Members \exposid{has_val}, \exposid{val}, and \exposid{unex} -are provided for exposition only. -\exposid{has_val} indicates whether the \tcode{expected} object +to allocate the object of type \tcode{T} or the object of type \tcode{E}. +Member \exposid{has_val} indicates whether the \tcode{expected} object contains an object of type \tcode{T}. \pnum @@ -7162,7 +7536,7 @@ \item \tcode{is_same_v, in_place_t>} is \tcode{false}; and \item -\tcode{is_same_v, remove_cvref_t>} is \tcode{false}; and +\tcode{is_same_v>} is \tcode{false}; and \item \tcode{remove_cvref_t} is not a specialization of \tcode{unexpected}; and \item @@ -7201,7 +7575,7 @@ \pnum \effects -Direct-non-list-initializes \exposid{unex} with \tcode{std::forward(e.value())}. +Direct-non-list-initializes \exposid{unex} with \tcode{std::forward(e.error())}. \pnum \ensures @@ -7386,6 +7760,10 @@ Then, if no exception was thrown, equivalent to: \tcode{\exposid{has_val} = rhs.has_value(); return *this;} +\pnum +\returns +\tcode{*this}. + \pnum \remarks This operator is defined as deleted unless: @@ -7448,6 +7826,10 @@ Then, if no exception was thrown, equivalent to: \tcode{has_val = rhs.has_value(); return *this;} +\pnum +\returns +\tcode{*this}. + \pnum \remarks The exception specification is equivalent to: @@ -7531,12 +7913,12 @@ \item If \tcode{has_value()} is \tcode{true}, equivalent to: \begin{codeblock} -@\exposid{reinit-expected}@(@\exposid{unex}@, @\exposid{val}@, std::forward(e.value())); +@\exposid{reinit-expected}@(@\exposid{unex}@, @\exposid{val}@, std::forward(e.error())); @\exposid{has_val}@ = false; \end{codeblock} \item Otherwise, equivalent to: -\tcode{\exposid{unex} = std::forward(e.value());} +\tcode{\exposid{unex} = std::forward(e.error());} \end{itemize} \pnum @@ -7896,12 +8278,12 @@ \begin{itemdescr} \pnum \mandates -The expression \tcode{x.error() == e.value()} is well-formed and +The expression \tcode{x.error() == e.error()} is well-formed and its result is convertible to \tcode{bool}. \pnum \returns -\tcode{!x.has_value() \&\& static_cast(x.error() == e.value())}. +\tcode{!x.has_value() \&\& static_cast(x.error() == e.error())}. \end{itemdescr} \rSec2[expected.void]{Partial specialization of \tcode{expected} for \tcode{void} types} @@ -7921,8 +8303,8 @@ // \ref{expected.void.ctor}, constructors constexpr expected() noexcept; - constexpr explicit(@\seebelow@) expected(const expected&); - constexpr explicit(@\seebelow@) expected(expected&&) noexcept(@\seebelow@); + constexpr expected(const expected&); + constexpr expected(expected&&) noexcept(@\seebelow@); template constexpr explicit(@\seebelow@) expected(const expected&); template @@ -7962,10 +8344,10 @@ constexpr void operator*() const noexcept; constexpr void value() const &; constexpr void value() &&; - constexpr const E& error() const &; - constexpr E& error() &; - constexpr const E&& error() const &&; - constexpr E&& error() &&; + constexpr const E& error() const & noexcept; + constexpr E& error() & noexcept; + constexpr const E&& error() const && noexcept; + constexpr E&& error() && noexcept; // \ref{expected.void.eq}, equality operators template requires is_void_v @@ -7981,6 +8363,21 @@ }; \end{codeblock} +\pnum +Any object of type \tcode{expected} either +represents a value of type \tcode{T}, or +contains a value of type \tcode{E} within its own storage. +Implementations are not permitted to use additional storage, +such as dynamic memory, to allocate the object of type \tcode{E}. +Member \exposid{has_val} indicates whether the \tcode{expected} object +represents a value of type \tcode{T}. + +\pnum +A program that instantiates +the definition of the template \tcode{expected} with +a type for the \tcode{E} parameter that +is not a valid template argument for \tcode{unexpected} is ill-formed. + \pnum \tcode{E} shall meet the requirements of \oldconcept{Destructible} (\tref{cpp17.destructible}). @@ -8127,7 +8524,7 @@ \pnum \effects Direct-non-list-initializes \exposid{unex} -with \tcode{std::forward(e.value())}. +with \tcode{std::forward(e.error())}. \pnum \ensures @@ -8272,7 +8669,7 @@ Otherwise, if \tcode{rhs.has_value()} is \tcode{true}, destroys \exposid{unex} and sets \exposid{has_val} to \tcode{true}. \item -Otherwise, equivalent to \tcode{\exposid{unex} = rhs.error()}. +Otherwise, equivalent to \tcode{\exposid{unex} = std::move(rhs.error())}. \end{itemize} \pnum @@ -8314,12 +8711,12 @@ \item If \tcode{has_value()} is \tcode{true}, equivalent to: \begin{codeblock} -construct_at(addressof(@\exposid{unex}@), std::forward(e.value())); +construct_at(addressof(@\exposid{unex}@), std::forward(e.error())); @\exposid{has_val}@ = false; \end{codeblock} \item Otherwise, equivalent to: -\tcode{\exposid{unex} = std::forward(e.value());} +\tcode{\exposid{unex} = std::forward(e.error());} \end{itemize} \pnum @@ -8449,8 +8846,8 @@ \indexlibrarymember{error}{expected}% \begin{itemdecl} -constexpr const E& error() const &; -constexpr E& error() &; +constexpr const E& error() const & noexcept; +constexpr E& error() & noexcept; \end{itemdecl} \begin{itemdescr} @@ -8465,8 +8862,8 @@ \indexlibrarymember{error}{expected}% \begin{itemdecl} -constexpr E&& error() &&; -constexpr const E&& error() const &&; +constexpr E&& error() && noexcept; +constexpr const E&& error() const && noexcept; \end{itemdecl} \begin{itemdescr} @@ -8508,12 +8905,12 @@ \begin{itemdescr} \pnum \mandates -The expression \tcode{x.error() == e.value()} is well-formed and +The expression \tcode{x.error() == e.error()} is well-formed and its result is convertible to \tcode{bool}. \pnum \returns -\tcode{!x.has_value() \&\& static_cast(x.error() == e.value())}. +\tcode{!x.has_value() \&\& static_cast(x.error() == e.error())}. \end{itemdescr} \rSec1[bitset]{Bitsets} @@ -8527,7 +8924,7 @@ and manipulating fixed-size sequences of bits. \begin{codeblock} -#include +#include // see \ref{string.syn} #include // for \tcode{istream}\iref{istream.syn}, \tcode{ostream}\iref{ostream.syn}, see \ref{iosfwd.syn} namespace std { @@ -8535,11 +8932,11 @@ // \ref{bitset.operators}, bitset operators template - bitset operator&(const bitset&, const bitset&) noexcept; + constexpr bitset operator&(const bitset&, const bitset&) noexcept; template - bitset operator|(const bitset&, const bitset&) noexcept; + constexpr bitset operator|(const bitset&, const bitset&) noexcept; template - bitset operator^(const bitset&, const bitset&) noexcept; + constexpr bitset operator^(const bitset&, const bitset&) noexcept; template basic_istream& operator>>(basic_istream& is, bitset& x); @@ -8560,23 +8957,23 @@ // bit reference class reference { friend class bitset; - reference() noexcept; + constexpr reference() noexcept; public: - reference(const reference&) = default; - ~reference(); - reference& operator=(bool x) noexcept; // for \tcode{b[i] = x;} - reference& operator=(const reference&) noexcept; // for \tcode{b[i] = b[j];} - bool operator~() const noexcept; // flips the bit - operator bool() const noexcept; // for \tcode{x = b[i];} - reference& flip() noexcept; // for \tcode{b[i].flip();} + constexpr reference(const reference&) = default; + constexpr ~reference(); + constexpr reference& operator=(bool x) noexcept; // for \tcode{b[i] = x;} + constexpr reference& operator=(const reference&) noexcept; // for \tcode{b[i] = b[j];} + constexpr bool operator~() const noexcept; // flips the bit + constexpr operator bool() const noexcept; // for \tcode{x = b[i];} + constexpr reference& flip() noexcept; // for \tcode{b[i].flip();} }; // \ref{bitset.cons}, constructors constexpr bitset() noexcept; constexpr bitset(unsigned long long val) noexcept; template - explicit bitset( + constexpr explicit bitset( const basic_string& str, typename basic_string::size_type pos = 0, typename basic_string::size_type n @@ -8584,47 +8981,47 @@ charT zero = charT('0'), charT one = charT('1')); template - explicit bitset( + constexpr explicit bitset( const charT* str, typename basic_string::size_type n = basic_string::npos, charT zero = charT('0'), charT one = charT('1')); // \ref{bitset.members}, bitset operations - bitset& operator&=(const bitset& rhs) noexcept; - bitset& operator|=(const bitset& rhs) noexcept; - bitset& operator^=(const bitset& rhs) noexcept; - bitset& operator<<=(size_t pos) noexcept; - bitset& operator>>=(size_t pos) noexcept; - bitset& set() noexcept; - bitset& set(size_t pos, bool val = true); - bitset& reset() noexcept; - bitset& reset(size_t pos); - bitset operator~() const noexcept; - bitset& flip() noexcept; - bitset& flip(size_t pos); + constexpr bitset& operator&=(const bitset& rhs) noexcept; + constexpr bitset& operator|=(const bitset& rhs) noexcept; + constexpr bitset& operator^=(const bitset& rhs) noexcept; + constexpr bitset& operator<<=(size_t pos) noexcept; + constexpr bitset& operator>>=(size_t pos) noexcept; + constexpr bitset& set() noexcept; + constexpr bitset& set(size_t pos, bool val = true); + constexpr bitset& reset() noexcept; + constexpr bitset& reset(size_t pos); + constexpr bitset operator~() const noexcept; + constexpr bitset& flip() noexcept; + constexpr bitset& flip(size_t pos); // element access constexpr bool operator[](size_t pos) const; // for \tcode{b[i];} - reference operator[](size_t pos); // for \tcode{b[i];} + constexpr reference operator[](size_t pos); // for \tcode{b[i];} - unsigned long to_ulong() const; - unsigned long long to_ullong() const; + constexpr unsigned long to_ulong() const; + constexpr unsigned long long to_ullong() const; template, class Allocator = allocator> - basic_string + constexpr basic_string to_string(charT zero = charT('0'), charT one = charT('1')) const; - size_t count() const noexcept; + constexpr size_t count() const noexcept; constexpr size_t size() const noexcept; - bool operator==(const bitset& rhs) const noexcept; - bool test(size_t pos) const; - bool all() const noexcept; - bool any() const noexcept; - bool none() const noexcept; - bitset operator<<(size_t pos) const noexcept; - bitset operator>>(size_t pos) const noexcept; + constexpr bool operator==(const bitset& rhs) const noexcept; + constexpr bool test(size_t pos) const; + constexpr bool all() const noexcept; + constexpr bool any() const noexcept; + constexpr bool none() const noexcept; + constexpr bitset operator<<(size_t pos) const noexcept; + constexpr bitset operator>>(size_t pos) const noexcept; }; // \ref{bitset.hash}, hash support @@ -8711,7 +9108,7 @@ \indexlibraryctor{bitset}% \begin{itemdecl} template - explicit bitset( + constexpr explicit bitset( const basic_string& str, typename basic_string::size_type pos = 0, typename basic_string::size_type n @@ -8762,7 +9159,7 @@ \indexlibraryctor{bitset}% \begin{itemdecl} template - explicit bitset( + constexpr explicit bitset( const charT* str, typename basic_string::size_type n = basic_string::npos, charT zero = charT('0'), @@ -8786,7 +9183,7 @@ \indexlibrarymember{operator\&=}{bitset}% \begin{itemdecl} -bitset& operator&=(const bitset& rhs) noexcept; +constexpr bitset& operator&=(const bitset& rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8803,7 +9200,7 @@ \indexlibrarymember{operator"|=}{bitset}% \begin{itemdecl} -bitset& operator|=(const bitset& rhs) noexcept; +constexpr bitset& operator|=(const bitset& rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8820,7 +9217,7 @@ \indexlibrarymember{operator\caret=}{bitset}% \begin{itemdecl} -bitset& operator^=(const bitset& rhs) noexcept; +constexpr bitset& operator^=(const bitset& rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8837,7 +9234,7 @@ \indexlibrarymember{operator<<=}{bitset}% \begin{itemdecl} -bitset& operator<<=(size_t pos) noexcept; +constexpr bitset& operator<<=(size_t pos) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8862,7 +9259,7 @@ \indexlibrarymember{operator>>=}{bitset}% \begin{itemdecl} -bitset& operator>>=(size_t pos) noexcept; +constexpr bitset& operator>>=(size_t pos) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8888,7 +9285,7 @@ \indexlibrary{\idxcode{set} (member)!\idxcode{bitset}}% \indexlibrary{\idxcode{bitset}!\idxcode{set}}% \begin{itemdecl} -bitset& set() noexcept; +constexpr bitset& set() noexcept; \end{itemdecl} \begin{itemdescr} @@ -8906,7 +9303,7 @@ \indexlibrary{\idxcode{set} (member)!\idxcode{bitset}}% \indexlibrary{\idxcode{bitset}!\idxcode{set}}% \begin{itemdecl} -bitset& set(size_t pos, bool val = true); +constexpr bitset& set(size_t pos, bool val = true); \end{itemdecl} \begin{itemdescr} @@ -8928,7 +9325,7 @@ \indexlibrarymember{reset}{bitset}% \begin{itemdecl} -bitset& reset() noexcept; +constexpr bitset& reset() noexcept; \end{itemdecl} \begin{itemdescr} @@ -8944,7 +9341,7 @@ \indexlibrarymember{reset}{bitset}% \begin{itemdecl} -bitset& reset(size_t pos); +constexpr bitset& reset(size_t pos); \end{itemdecl} \begin{itemdescr} @@ -8965,7 +9362,7 @@ \indexlibrarymember{operator\~{}}{bitset}% \begin{itemdecl} -bitset operator~() const noexcept; +constexpr bitset operator~() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -8983,7 +9380,7 @@ \indexlibrarymember{flip}{bitset}% \begin{itemdecl} -bitset& flip() noexcept; +constexpr bitset& flip() noexcept; \end{itemdecl} \begin{itemdescr} @@ -8999,7 +9396,7 @@ \indexlibrarymember{flip}{bitset}% \begin{itemdecl} -bitset& flip(size_t pos); +constexpr bitset& flip(size_t pos); \end{itemdecl} \begin{itemdescr} @@ -9020,7 +9417,7 @@ \indexlibrarymember{to_ulong}{bitset}% \begin{itemdecl} -unsigned long to_ulong() const; +constexpr unsigned long to_ulong() const; \end{itemdecl} \begin{itemdescr} @@ -9038,7 +9435,7 @@ \indexlibrarymember{to_ullong}{bitset}% \begin{itemdecl} -unsigned long long to_ullong() const; +constexpr unsigned long long to_ullong() const; \end{itemdecl} \begin{itemdescr} @@ -9059,7 +9456,7 @@ template, class Allocator = allocator> - basic_string + constexpr basic_string to_string(charT zero = charT('0'), charT one = charT('1')) const; \end{itemdecl} @@ -9084,7 +9481,7 @@ \indexlibrarymember{count}{bitset}% \begin{itemdecl} -size_t count() const noexcept; +constexpr size_t count() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -9107,7 +9504,7 @@ \indexlibrarymember{operator==}{bitset}% \begin{itemdecl} -bool operator==(const bitset& rhs) const noexcept; +constexpr bool operator==(const bitset& rhs) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -9120,7 +9517,7 @@ \indexlibrarymember{test}{bitset}% \begin{itemdecl} -bool test(size_t pos) const; +constexpr bool test(size_t pos) const; \end{itemdecl} \begin{itemdescr} @@ -9140,7 +9537,7 @@ \indexlibrarymember{all}{bitset}% \begin{itemdecl} -bool all() const noexcept; +constexpr bool all() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -9153,7 +9550,7 @@ \indexlibrary{\idxcode{any} (member)!\idxcode{bitset}}% \indexlibrary{\idxcode{bitset}!\idxcode{any}}% \begin{itemdecl} -bool any() const noexcept; +constexpr bool any() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -9164,7 +9561,7 @@ \indexlibrarymember{none}{bitset}% \begin{itemdecl} -bool none() const noexcept; +constexpr bool none() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -9175,7 +9572,7 @@ \indexlibrarymember{operator<<}{bitset}% \begin{itemdecl} -bitset operator<<(size_t pos) const noexcept; +constexpr bitset operator<<(size_t pos) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -9186,7 +9583,7 @@ \indexlibrarymember{operator>>}{bitset}% \begin{itemdecl} -bitset operator>>(size_t pos) const noexcept; +constexpr bitset operator>>(size_t pos) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -9217,7 +9614,7 @@ \indexlibrarymember{operator[]}{bitset}% \begin{itemdecl} -bitset::reference operator[](size_t pos); +constexpr bitset::reference operator[](size_t pos); \end{itemdecl} \begin{itemdescr} @@ -9266,7 +9663,7 @@ \indexlibrarymember{operator\&}{bitset}% \begin{itemdecl} template - bitset operator&(const bitset& lhs, const bitset& rhs) noexcept; + constexpr bitset operator&(const bitset& lhs, const bitset& rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -9278,7 +9675,7 @@ \indexlibrarymember{operator"|}{bitset}% \begin{itemdecl} template - bitset operator|(const bitset& lhs, const bitset& rhs) noexcept; + constexpr bitset operator|(const bitset& lhs, const bitset& rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -9290,7 +9687,7 @@ \indexlibrarymember{operator\caret}{bitset}% \begin{itemdecl} template - bitset operator^(const bitset& lhs, const bitset& rhs) noexcept; + constexpr bitset operator^(const bitset& lhs, const bitset& rhs) noexcept; \end{itemdecl} \begin{itemdescr} @@ -9391,109 +9788,115 @@ namespace std { // \ref{func.invoke}, invoke template - constexpr invoke_result_t invoke(F&& f, Args&&... args) + constexpr invoke_result_t invoke(F&& f, Args&&... args) // freestanding noexcept(is_nothrow_invocable_v); template - constexpr R invoke_r(F&& f, Args&&... args) + constexpr R invoke_r(F&& f, Args&&... args) // freestanding noexcept(is_nothrow_invocable_r_v); // \ref{refwrap}, \tcode{reference_wrapper} - template class reference_wrapper; + template class reference_wrapper; // freestanding - template constexpr reference_wrapper ref(T&) noexcept; - template constexpr reference_wrapper cref(const T&) noexcept; - template void ref(const T&&) = delete; - template void cref(const T&&) = delete; + template constexpr reference_wrapper ref(T&) noexcept; // freestanding + template constexpr reference_wrapper cref(const T&) noexcept; // freestanding + template void ref(const T&&) = delete; // freestanding + template void cref(const T&&) = delete; // freestanding - template constexpr reference_wrapper ref(reference_wrapper) noexcept; - template constexpr reference_wrapper cref(reference_wrapper) noexcept; + template + constexpr reference_wrapper ref(reference_wrapper) noexcept; // freestanding + template + constexpr reference_wrapper cref(reference_wrapper) noexcept; // freestanding // \ref{arithmetic.operations}, arithmetic operations - template struct plus; - template struct minus; - template struct multiplies; - template struct divides; - template struct modulus; - template struct negate; - template<> struct plus; - template<> struct minus; - template<> struct multiplies; - template<> struct divides; - template<> struct modulus; - template<> struct negate; + template struct plus; // freestanding + template struct minus; // freestanding + template struct multiplies; // freestanding + template struct divides; // freestanding + template struct modulus; // freestanding + template struct negate; // freestanding + template<> struct plus; // freestanding + template<> struct minus; // freestanding + template<> struct multiplies; // freestanding + template<> struct divides; // freestanding + template<> struct modulus; // freestanding + template<> struct negate; // freestanding // \ref{comparisons}, comparisons - template struct equal_to; - template struct not_equal_to; - template struct greater; - template struct less; - template struct greater_equal; - template struct less_equal; - template<> struct equal_to; - template<> struct not_equal_to; - template<> struct greater; - template<> struct less; - template<> struct greater_equal; - template<> struct less_equal; + template struct equal_to; // freestanding + template struct not_equal_to; // freestanding + template struct greater; // freestanding + template struct less; // freestanding + template struct greater_equal; // freestanding + template struct less_equal; // freestanding + template<> struct equal_to; // freestanding + template<> struct not_equal_to; // freestanding + template<> struct greater; // freestanding + template<> struct less; // freestanding + template<> struct greater_equal; // freestanding + template<> struct less_equal; // freestanding // \ref{comparisons.three.way}, class \tcode{compare_three_way} - struct compare_three_way; + struct compare_three_way; // freestanding // \ref{logical.operations}, logical operations - template struct logical_and; - template struct logical_or; - template struct logical_not; - template<> struct logical_and; - template<> struct logical_or; - template<> struct logical_not; + template struct logical_and; // freestanding + template struct logical_or; // freestanding + template struct logical_not; // freestanding + template<> struct logical_and; // freestanding + template<> struct logical_or; // freestanding + template<> struct logical_not; // freestanding // \ref{bitwise.operations}, bitwise operations - template struct bit_and; - template struct bit_or; - template struct bit_xor; - template struct bit_not; - template<> struct bit_and; - template<> struct bit_or; - template<> struct bit_xor; - template<> struct bit_not; + template struct bit_and; // freestanding + template struct bit_or; // freestanding + template struct bit_xor; // freestanding + template struct bit_not; // freestanding + template<> struct bit_and; // freestanding + template<> struct bit_or; // freestanding + template<> struct bit_xor; // freestanding + template<> struct bit_not; // freestanding // \ref{func.identity}, identity - struct identity; + struct identity; // freestanding // \ref{func.not.fn}, function template \tcode{not_fn} - template constexpr @\unspec@ not_fn(F&& f); + template constexpr @\unspec@ not_fn(F&& f); // freestanding // \ref{func.bind.partial}, function templates \tcode{bind_front} and \tcode{bind_back} - template constexpr @\unspec@ bind_front(F&&, Args&&...); - template constexpr @\unspec@ bind_back(F&&, Args&&...); + template + constexpr @\unspec@ bind_front(F&&, Args&&...); // freestanding + template + constexpr @\unspec@ bind_back(F&&, Args&&...); // freestanding // \ref{func.bind}, bind - template struct is_bind_expression; + template struct is_bind_expression; // freestanding template - inline constexpr bool @\libglobal{is_bind_expression_v}@ = is_bind_expression::value; - template struct is_placeholder; + inline constexpr bool @\libglobal{is_bind_expression_v}@ = // freestanding + is_bind_expression::value; + template struct is_placeholder; // freestanding template - inline constexpr int @\libglobal{is_placeholder_v}@ = is_placeholder::value; + inline constexpr int @\libglobal{is_placeholder_v}@ = // freestanding + is_placeholder::value; template - constexpr @\unspec@ bind(F&&, BoundArgs&&...); + constexpr @\unspec@ bind(F&&, BoundArgs&&...); // freestanding template - constexpr @\unspec@ bind(F&&, BoundArgs&&...); + constexpr @\unspec@ bind(F&&, BoundArgs&&...); // freestanding namespace placeholders { // \tcode{\placeholder{M}} is the \impldef{number of placeholders for bind expressions} number of placeholders - @\seebelownc@ _1; - @\seebelownc@ _2; + @\seebelownc@ _1; // freestanding + @\seebelownc@ _2; // freestanding . . . - @\seebelownc@ _@\placeholdernc{M}@; + @\seebelownc@ _@\placeholdernc{M}@; // freestanding } // \ref{func.memfn}, member function adaptors template - constexpr @\unspec@ mem_fn(R T::*) noexcept; + constexpr @\unspec@ mem_fn(R T::*) noexcept; // freestanding // \ref{func.wrap}, polymorphic function wrappers class bad_function_call; @@ -9515,8 +9918,8 @@ class move_only_function; // \seebelow // \ref{func.search}, searchers - template> - class default_searcher; + template> + class default_searcher; // freestanding template::value_type>, @@ -9528,18 +9931,18 @@ class BinaryPredicate = equal_to<>> class boyer_moore_horspool_searcher; - // \ref{unord.hash}, class template hash + // \ref{unord.hash}, class template \tcode{hash} template - struct hash; + struct hash; // freestanding namespace ranges { // \ref{range.cmp}, concept-constrained comparisons - struct equal_to; - struct not_equal_to; - struct greater; - struct less; - struct greater_equal; - struct less_equal; + struct equal_to; // freestanding + struct not_equal_to; // freestanding + struct greater; // freestanding + struct less; // freestanding + struct greater_equal; // freestanding + struct less_equal; // freestanding } } \end{codeblock} @@ -9936,7 +10339,7 @@ \begin{itemdescr} \pnum \returns -\tcode{reference_wrapper (t)}. +\tcode{reference_wrapper(t)}. \end{itemdescr} \indexlibrarymember{cref}{reference_wrapper}% @@ -11398,6 +11801,9 @@ \end{codeblock}% \indextext{function object!binders|)} +\pnum +Placeholders are freestanding entities\iref{freestanding.entity}. + \rSec2[func.memfn]{Function template \tcode{mem_fn}}% \indextext{function object!\idxcode{mem_fn}|(} @@ -11679,10 +12085,20 @@ \begin{itemdescr} \pnum \constraints -\tcode{\&F::operator()} is well-formed when treated as an unevaluated operand and -\tcode{decltype(\brk{}\&F::operator())} is of the form +\tcode{\&F::operator()} is well-formed when treated as an unevaluated operand and either +\begin{itemize} +\item +\tcode{F::operator()} is a non-static member function and +\tcode{decltype(\brk{}\&F::operator())} is either of the form \tcode{R(G::*)(A...)}~\cv{}~\tcode{\opt{\&}~\opt{noexcept}} -for a class type \tcode{G}. +or of the form +\tcode{R(*)(G, A...)~\opt{noexcept}} +for a type \tcode{G}, or +\item +\tcode{F::operator()} is a static member function and +\tcode{decltype(\&F::operator())} is of the form +\tcode{R(*)(A...) \opt{noexcept}}. +\end{itemize} \pnum \remarks @@ -12138,7 +12554,7 @@ \constraints \begin{itemize} \item -\tcode{is_constructible_v\&, ArgTypes...>} is +\tcode{is_constructible_v\&, Args...>} is \tcode{true}, and \item \tcode{\exposid{is-callable-from}} is \tcode{true}. @@ -12158,7 +12574,7 @@ \ensures \tcode{*this} has a target object of type \tcode{VT} direct-non-list-initialized with -\tcode{ilist, std::for\-ward(args)...}. +\tcode{ilist, std::for\-ward(args)...}. \pnum \throws @@ -12353,7 +12769,7 @@ \indexlibraryctor{default_searcher}% \begin{itemdecl} -constexpr default_searcher(ForwardIterator pat_first, ForwardIterator pat_last, +constexpr default_searcher(ForwardIterator1 pat_first, ForwardIterator1 pat_last, BinaryPredicate pred = BinaryPredicate()); \end{itemdecl} @@ -12444,7 +12860,8 @@ \tcode{pat_first_} with \tcode{pat_first}, \tcode{pat_last_} with \tcode{pat_last}, \tcode{hash_} with \tcode{hf}, and -\tcode{pred_} with \tcode{pred}. +% FIXME: The mbox prevents TeX from adding a bizarre hyphen after pred_. +\mbox{\tcode{pred_}} with \tcode{pred}. \pnum \throws @@ -12543,7 +12960,8 @@ \tcode{pat_first_} with \tcode{pat_first}, \tcode{pat_last_} with \tcode{pat_last}, \tcode{hash_} with \tcode{hf}, and -\tcode{pred_} with \tcode{pred}. +% FIXME: The mbox prevents TeX from adding a bizarre hyphen after pred_. +\mbox{\tcode{pred_}} with \tcode{pred}. \pnum \throws @@ -13013,6 +13431,18 @@ \rSec2[charconv.syn]{Header \tcode{} synopsis} +\pnum +When a function is specified +with a type placeholder of \tcode{\placeholder{integer-type}}, +the implementation provides overloads +for all cv-unqualified signed and unsigned integer types and \tcode{char} +in lieu of \tcode{\placeholder{integer-type}}. +When a function is specified +with a type placeholder of \tcode{\placeholder{floating-point-type}}, +the implementation provides overloads +for all cv-unqualified floating-point types\iref{basic.fundamental} +in lieu of \tcode{\placeholder{floating-point-type}}. + \indexheader{charconv}% \begin{codeblock} @% @@ -13041,22 +13471,12 @@ friend bool operator==(const to_chars_result&, const to_chars_result&) = default; }; - to_chars_result to_chars(char* first, char* last, @\seebelow@ value, int base = 10); + constexpr to_chars_result to_chars(char* first, char* last, @\placeholder{integer-type}@ value, int base = 10); to_chars_result to_chars(char* first, char* last, bool value, int base = 10) = delete; - to_chars_result to_chars(char* first, char* last, float value); - to_chars_result to_chars(char* first, char* last, double value); - to_chars_result to_chars(char* first, char* last, long double value); - - to_chars_result to_chars(char* first, char* last, float value, chars_format fmt); - to_chars_result to_chars(char* first, char* last, double value, chars_format fmt); - to_chars_result to_chars(char* first, char* last, long double value, chars_format fmt); - - to_chars_result to_chars(char* first, char* last, float value, - chars_format fmt, int precision); - to_chars_result to_chars(char* first, char* last, double value, - chars_format fmt, int precision); - to_chars_result to_chars(char* first, char* last, long double value, + to_chars_result to_chars(char* first, char* last, @\placeholder{floating-point-type}@ value); + to_chars_result to_chars(char* first, char* last, @\placeholder{floating-point-type}@ value, chars_format fmt); + to_chars_result to_chars(char* first, char* last, @\placeholder{floating-point-type}@ value, chars_format fmt, int precision); @% \indexlibraryglobal{from_chars_result}% @@ -13070,14 +13490,10 @@ friend bool operator==(const from_chars_result&, const from_chars_result&) = default; }; - from_chars_result from_chars(const char* first, const char* last, - @\seebelow@& value, int base = 10); + constexpr from_chars_result from_chars(const char* first, const char* last, + @\placeholder{integer-type}@& value, int base = 10); - from_chars_result from_chars(const char* first, const char* last, float& value, - chars_format fmt = chars_format::general); - from_chars_result from_chars(const char* first, const char* last, double& value, - chars_format fmt = chars_format::general); - from_chars_result from_chars(const char* first, const char* last, long double& value, + from_chars_result from_chars(const char* first, const char* last, @\placeholder{floating-point-type}@& value, chars_format fmt = chars_format::general); } \end{codeblock} @@ -13144,7 +13560,7 @@ \indexlibraryglobal{to_chars}% \begin{itemdecl} -to_chars_result to_chars(char* first, char* last, @\seebelow@ value, int base = 10); +constexpr to_chars_result to_chars(char* first, char* last, @\placeholder{integer-type}@ value, int base = 10); \end{itemdecl} \begin{itemdescr} @@ -13165,20 +13581,11 @@ \pnum \throws Nothing. - -\pnum -\remarks -The implementation shall provide overloads -for all signed and unsigned integer types -and \tcode{char} -as the type of the parameter \tcode{value}. \end{itemdescr} \indexlibraryglobal{to_chars}% \begin{itemdecl} -to_chars_result to_chars(char* first, char* last, float value); -to_chars_result to_chars(char* first, char* last, double value); -to_chars_result to_chars(char* first, char* last, long double value); +to_chars_result to_chars(char* first, char* last, @\placeholder{floating-point-type}@ value); \end{itemdecl} \begin{itemdescr} @@ -13199,9 +13606,7 @@ \indexlibraryglobal{to_chars}% \begin{itemdecl} -to_chars_result to_chars(char* first, char* last, float value, chars_format fmt); -to_chars_result to_chars(char* first, char* last, double value, chars_format fmt); -to_chars_result to_chars(char* first, char* last, long double value, chars_format fmt); +to_chars_result to_chars(char* first, char* last, @\placeholder{floating-point-type}@ value, chars_format fmt); \end{itemdecl} \begin{itemdescr} @@ -13223,11 +13628,7 @@ \indexlibraryglobal{to_chars}% \begin{itemdecl} -to_chars_result to_chars(char* first, char* last, float value, - chars_format fmt, int precision); -to_chars_result to_chars(char* first, char* last, double value, - chars_format fmt, int precision); -to_chars_result to_chars(char* first, char* last, long double value, +to_chars_result to_chars(char* first, char* last, @\placeholder{floating-point-type}@ value, chars_format fmt, int precision); \end{itemdecl} @@ -13290,8 +13691,8 @@ \indexlibraryglobal{from_chars}% \begin{itemdecl} -from_chars_result from_chars(const char* first, const char* last, - @\seebelow@&@\itcorr[-1]@ value, int base = 10); +constexpr from_chars_result from_chars(const char* first, const char* last, + @\placeholder{integer-type}@&@\itcorr[-1]@ value, int base = 10); \end{itemdecl} \begin{itemdescr} @@ -13314,22 +13715,11 @@ \pnum \throws Nothing. - -\pnum -\remarks -The implementation shall provide overloads -for all signed and unsigned integer types -and \tcode{char} -as the referenced type of the parameter \tcode{value}. \end{itemdescr} \indexlibraryglobal{from_chars}% \begin{itemdecl} -from_chars_result from_chars(const char* first, const char* last, float& value, - chars_format fmt = chars_format::general); -from_chars_result from_chars(const char* first, const char* last, double& value, - chars_format fmt = chars_format::general); -from_chars_result from_chars(const char* first, const char* last, long double& value, +from_chars_result from_chars(const char* first, const char* last, @\placeholder{floating-point-type}@& value, chars_format fmt = chars_format::general); \end{itemdecl} @@ -13404,26 +13794,24 @@ using format_args = basic_format_args; using wformat_args = basic_format_args; - // \ref{format.fmt.string}, class template \exposid{basic-format-string} + // \ref{format.fmt.string}, class template \tcode{basic_format_string} template - struct @\exposid{basic-format-string}@; // \expos + struct basic_format_string; template - using @\exposid{format-string}@ = // \expos - @\exposid{basic-format-string}@...>; + using @\libglobal{format_string}@ = basic_format_string...>; template - using @\exposid{wformat-string}@ = // \expos - @\exposid{basic-format-string}@...>; + using @\libglobal{wformat_string}@ = basic_format_string...>; // \ref{format.functions}, formatting functions template - string format(@\exposid{format-string}@ fmt, Args&&... args); + string format(format_string fmt, Args&&... args); template - wstring format(@\exposid{wformat-string}@ fmt, Args&&... args); + wstring format(wformat_string fmt, Args&&... args); template - string format(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); + string format(const locale& loc, format_string fmt, Args&&... args); template - wstring format(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); + wstring format(const locale& loc, wformat_string fmt, Args&&... args); string vformat(string_view fmt, format_args args); wstring vformat(wstring_view fmt, wformat_args args); @@ -13431,13 +13819,13 @@ wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); template - Out format_to(Out out, @\exposid{format-string}@ fmt, Args&&... args); + Out format_to(Out out, format_string fmt, Args&&... args); template - Out format_to(Out out, @\exposid{wformat-string}@ fmt, Args&&... args); + Out format_to(Out out, wformat_string fmt, Args&&... args); template - Out format_to(Out out, const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); + Out format_to(Out out, const locale& loc, format_string fmt, Args&&... args); template - Out format_to(Out out, const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); + Out format_to(Out out, const locale& loc, wformat_string fmt, Args&&... args); template Out vformat_to(Out out, string_view fmt, format_args args); @@ -13454,36 +13842,82 @@ }; template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{format-string}@ fmt, Args&&... args); + format_string fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{wformat-string}@ fmt, Args&&... args); + wformat_string fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - const locale& loc, @\exposid{format-string}@ fmt, + const locale& loc, format_string fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - const locale& loc, @\exposid{wformat-string}@ fmt, + const locale& loc, wformat_string fmt, Args&&... args); template - size_t formatted_size(@\exposid{format-string}@ fmt, Args&&... args); + size_t formatted_size(format_string fmt, Args&&... args); template - size_t formatted_size(@\exposid{wformat-string}@ fmt, Args&&... args); + size_t formatted_size(wformat_string fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); + size_t formatted_size(const locale& loc, format_string fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); + size_t formatted_size(const locale& loc, wformat_string fmt, Args&&... args); // \ref{format.formatter}, formatter template struct formatter; + // \ref{format.formattable}, concept \libconcept{formattable} + template + concept formattable = @\seebelow@; + + template + concept @\defexposconcept{const-formattable-range}@ = // \expos + ranges::@\libconcept{input_range}@ && + @\libconcept{formattable}@, charT>; + + template + using @\exposid{fmt-maybe-const}@ = // \expos + conditional_t<@\exposconcept{const-formattable-range}@, const R, R>; + // \ref{format.parse.ctx}, class template \tcode{basic_format_parse_context} template class basic_format_parse_context; using format_parse_context = basic_format_parse_context; using wformat_parse_context = basic_format_parse_context; + // \ref{format.range}, formatting of ranges + // \ref{format.range.fmtkind}, variable template \tcode{format_kind} + enum class range_format { + disabled, + map, + set, + sequence, + string, + debug_string + }; + + template + constexpr @\unspec@ format_kind = @\unspec@; + + template + requires @\libconcept{same_as}@> + constexpr range_format format_kind = @\seebelow@; + + // \ref{format.range.formatter}, class template \tcode{range_formatter} + template + requires @\libconcept{same_as}@, T> && @\libconcept{formattable}@ + class range_formatter; + + // \ref{format.range.fmtdef}, class template \exposid{range-default-formatter} + template + struct @\exposid{range-default-formatter}@; // \expos + + // \ref{format.range.fmtmap}, \ref{format.range.fmtset}, \ref{format.range.fmtstr}, specializations for maps, sets, and strings + template + requires (format_kind != range_format::disabled) && + @\libconcept{formattable}@, charT> + struct formatter : @\exposid{range-default-formatter}@, R, charT> { }; + // \ref{format.arguments}, arguments // \ref{format.arg}, class template \tcode{basic_format_arg} template class basic_format_arg; @@ -13704,7 +14138,7 @@ \begin{ncbnf} \fmtnontermdef{type} \textnormal{one of}\br - \terminal{a A b B c d e E f F g G o p s x X} + \terminal{a A b B c d e E f F g G o p s x X ?} \end{ncbnf} \pnum @@ -13839,14 +14273,32 @@ % alter its behavior? trailing zeros are not removed from the result. +\pnum +A zero (\tcode{0}) character +preceding the \fmtgrammarterm{width} field +pads the field with leading zeros (following any indication of sign or base) +to the field width, +except when applied to an infinity or NaN. +This option is only valid for +arithmetic types other than \tcode{charT} and \tcode{bool} +or when an integer presentation type is specified. +If the \tcode{0} character and an \fmtgrammarterm{align} option both appear, +the \tcode{0} character is ignored. +\begin{example} +\begin{codeblock} +char c = 120; +string s1 = format("{:+06d}", c); // value of \tcode{s1} is \tcode{"+00120"} +string s2 = format("{:#06x}", 0xa); // value of \tcode{s2} is \tcode{"0x000a"} +string s3 = format("{:<06}", -42); // value of \tcode{s3} is \tcode{"-42\ \ \ "} (\tcode{0} is ignored because of \tcode{<} alignment) +\end{codeblock} +\end{example} + \pnum If \tcode{\{ \opt{\fmtgrammarterm{arg-id}} \}} is used in a \fmtgrammarterm{width} or \fmtgrammarterm{precision}, the value of the corresponding formatting argument is used in its place. If the corresponding formatting argument is not of integral type, or -its value is -negative for \fmtgrammarterm{precision} or -non-positive for \fmtgrammarterm{width}, +its value is negative, an exception of type \tcode{format_error} is thrown. \pnum @@ -13912,26 +14364,6 @@ \pnum For a string in a non-Unicode encoding, the width of a string is unspecified. -\pnum -A zero (\tcode{0}) character -preceding the \fmtgrammarterm{width} field -pads the field with leading zeros (following any indication of sign or base) -to the field width, -except when applied to an infinity or NaN. -This option is only valid for -arithmetic types other than \tcode{charT} and \tcode{bool} -or when an integer presentation type is specified. -If the \tcode{0} character and an \fmtgrammarterm{align} option both appear, -the \tcode{0} character is ignored. -\begin{example} -\begin{codeblock} -char c = 120; -string s1 = format("{:+06d}", c); // value of \tcode{s1} is \tcode{"+00120"} -string s2 = format("{:#06x}", 0xa); // value of \tcode{s2} is \tcode{"0x000a"} -string s3 = format("{:<06}", -42); // value of \tcode{s3} is \tcode{"-42\ \ \ "} (\tcode{0} is ignored because of \tcode{<} alignment) -\end{codeblock} -\end{example} - \pnum % FIXME: What if it's an arg-id? The \fmtgrammarterm{nonnegative-integer} in @@ -13982,6 +14414,10 @@ \lhdr{Type} & \rhdr{Meaning} \\ \rowsep none, \tcode{s} & Copies the string to the output. +\\ \rowsep +% +\tcode{?} & +Copies the escaped string\iref{format.string.escaped} to the output. \\ \end{floattable} @@ -14079,6 +14515,10 @@ % \tcode{b}, \tcode{B}, \tcode{d}, \tcode{o}, \tcode{x}, \tcode{X} & As specified in \tref{format.type.int}. +\\ \rowsep +% +\tcode{?} & +Copies the escaped character\iref{format.string.escaped} to the output. \\ \end{floattable} @@ -14215,21 +14655,25 @@ Failure to allocate storage is reported by throwing an exception as described in~\ref{res.on.exception.handling}. -\rSec2[format.fmt.string]{Class template \exposid{basic-format-string}} +\rSec2[format.fmt.string]{Class template \tcode{basic_format_string}} \begin{codeblock} -template -struct @\exposid{basic-format-string}@ { // \expos -private: - basic_string_view @\exposid{str}@; // \expos +namespace std { + template + struct @\libglobal{basic_format_string}@ { + private: + basic_string_view @\exposidnc{str}@; // \expos -public: - template consteval @\exposid{basic-format-string}@(const T& s); -}; + public: + template consteval basic_format_string(const T& s); + + constexpr basic_string_view get() const noexcept { return @\exposid{str}@; } + }; +} \end{codeblock} \begin{itemdecl} -template consteval @\exposid{basic-format-string}@(const T& s); +template consteval basic_format_string(const T& s); \end{itemdecl} \begin{itemdescr} @@ -14259,7 +14703,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - string format(@\exposid{format-string}@ fmt, Args&&... args); + string format(format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14274,7 +14718,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - wstring format(@\exposid{wformat-string}@ fmt, Args&&... args); + wstring format(wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14289,7 +14733,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - string format(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); + string format(const locale& loc, format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14304,7 +14748,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - wstring format(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); + wstring format(const locale& loc, wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14340,7 +14784,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, @\exposid{format-string}@ fmt, Args&&... args); + Out format_to(Out out, format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14355,7 +14799,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, @\exposid{wformat-string}@ fmt, Args&&... args); + Out format_to(Out out, wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14370,7 +14814,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); + Out format_to(Out out, const locale& loc, format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14385,7 +14829,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); + Out format_to(Out out, const locale& loc, wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14443,17 +14887,17 @@ \begin{itemdecl} template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{format-string}@ fmt, Args&&... args); + format_string fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{wformat-string}@ fmt, Args&&... args); + wformat_string fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - const locale& loc, @\exposid{format-string}@ fmt, + const locale& loc, format_string fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - const locale& loc, @\exposid{wformat-string}@ fmt, + const locale& loc, wformat_string fmt, Args&&... args); \end{itemdecl} @@ -14499,13 +14943,13 @@ \indexlibraryglobal{formatted_size}% \begin{itemdecl} template - size_t formatted_size(@\exposid{format-string}@ fmt, Args&&... args); + size_t formatted_size(format_string fmt, Args&&... args); template - size_t formatted_size(@\exposid{wformat-string}@ fmt, Args&&... args); + size_t formatted_size(wformat_string fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); + size_t formatted_size(const locale& loc, format_string fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); + size_t formatted_size(const locale& loc, wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -14636,6 +15080,35 @@ \\ \end{concepttable} +\rSec3[format.formattable]{Concept \cname{formattable}} + +\pnum +Let \tcode{\placeholder{fmt-iter-for}} be an unspecified type +that models +\tcode{\libconcept{output_iterator}}\iref{iterator.concept.output}. + +\begin{codeblock} +template + concept @\deflibconcept{formattable}@ = + @\libconcept{semiregular}@, charT>> && + requires(formatter, charT> f, + const formatter, charT> cf, + T t, + basic_format_context<@\placeholder{fmt-iter-for}@, charT> fc, + basic_format_parse_context pc) { + { f.parse(pc) } -> @\libconcept{same_as}@::iterator>; + { cf.format(t, fc) } -> @\libconcept{same_as}@<@\placeholder{fmt-iter-for}@>; + }; +\end{codeblock} + +\pnum +A type \tcode{T} and a character type \tcode{charT} +model \libconcept{formattable} +if \tcode{formatter, charT>} meets +the \newoldconcept{BasicFormatter} requirements\iref{formatter.requirements} +and, if \tcode{remove_reference_t} is const-qualified, +the \newoldconcept{Formatter} requirements. + \rSec3[format.formatter.spec]{Formatter specializations} \indexlibraryglobal{formatter}% @@ -14649,12 +15122,19 @@ Let \tcode{charT} be either \tcode{char} or \keyword{wchar_t}. Each specialization of \tcode{formatter} is either enabled or disabled, as described below. +\indextext{\idxcode{formatter}!debug-enabled specialization of}% +A \defn{debug-enabled} specialization of \tcode{formatter} +additionally provides +a public, constexpr, non-static member function \tcode{set_debug_format()} +which modifies the state of the \tcode{formatter} to be as if +the type of the \fmtgrammarterm{std-format-spec} +parsed by the last call to \tcode{parse} were \tcode{?}. Each header that declares the template \tcode{formatter} provides the following enabled specializations: \begin{itemize} \item \indexlibrary{\idxcode{formatter}!specializations!character types}% -The specializations +The debug-enabled specializations \begin{codeblock} template<> struct formatter; template<> struct formatter; @@ -14664,10 +15144,11 @@ \item \indexlibrary{\idxcode{formatter}!specializations!string types}% For each \tcode{charT}, -the string type specializations +the debug-enabled string type specializations \begin{codeblock} template<> struct formatter; template<> struct formatter; +template struct formatter; template struct formatter; template struct formatter, charT>; @@ -14761,6 +15242,151 @@ \end{codeblock} \end{example} +\rSec3[format.string.escaped]{Formatting escaped characters and strings} + +\pnum +\indextext{string!formatted as escaped}% +\indextext{character!formatted as escaped}% +A character or string can be formatted as \defn{escaped} +to make it more suitable for debugging or for logging. + +\pnum +The escaped string \placeholder{E} representation of a string \placeholder{S} +is constructed by encoding a sequence of characters as follows. +The associated character encoding \placeholder{CE} +for \tcode{charT}~(\tref{lex.string.literal}) +is used to both interpret \placeholder{S} and construct \placeholder{E}. + +\begin{itemize} +\item +\unicode{0022}{quotation mark} (\tcode{"}) is appended to \placeholder{E}. + +\item +For each code unit sequence \placeholder{X} in \placeholder{S} that either +encodes a single character, +is a shift sequence, or +is a sequence of ill-formed code units, +processing is in order as follows: + +\begin{itemize} +\item +If \placeholder{X} encodes a single character \placeholder{C}, then: + +\begin{itemize} +\item +If \placeholder{C} is one of the characters in \tref{format.escape.sequences}, +then the two characters shown as the corresponding escape sequence +are appended to \placeholder{E}. + +\item +Otherwise, if \placeholder{C} is not \unicode{0020}{space} and + +\begin{itemize} +\item +\placeholder{CE} is a Unicode encoding and +\placeholder{C} corresponds to either +a UCS scalar value whose Unicode property \tcode{General_Category} +has a value in the groups \tcode{Separator} (\tcode{Z}) or \tcode{Other} (\tcode{C}) or to +a UCS scalar value which has the Unicode property \tcode{Grapheme_Extend=Yes}, +as described by table 12 of UAX \#44, or + +\item +\placeholder{CE} is not a Unicode encoding and +\placeholder{C} is one of an implementation-defined set +of separator or non-printable characters +\end{itemize} + +then the sequence \tcode{\textbackslash u\{\placeholder{hex-digit-sequence}\}} +is appended to \placeholder{E}, +where \tcode{\placeholder{hex-digit-sequence}} +is the shortest hexadecimal representation +of \placeholder{C} using lower-case hexadecimal digits. + +\item +Otherwise, \placeholder{C} is appended to \placeholder{E}. +\end{itemize} + +\item +Otherwise, if \placeholder{X} is a shift sequence, +the effect on \placeholder{E} and further decoding of \placeholder{S} +is unspecified. + +\recommended +A shift sequence should be represented in \placeholder{E} +such that the original code unit sequence of \placeholder{S} +can be reconstructed. + +\item +Otherwise (\placeholder{X} is a sequence of ill-formed code units), +each code unit \placeholder{U} is appended to \placeholder{E} in order +as the sequence \tcode{\textbackslash x\{\placeholder{hex-digit-sequence}\}}, +where \tcode{\placeholder{hex-digit-sequence}} +is the shortest hexadecimal representation of \placeholder{U} +using lower-case hexadecimal digits. +\end{itemize} + +\item +Finally, \unicode{0022}{quotation mark} (\tcode{"}) +is appended to \placeholder{E}. +\end{itemize} +% +\begin{floattable}{Mapping of characters to escape sequences}{format.escape.sequences}{ll} +\topline +\lhdr{Character} & \rhdr{Escape sequence} \\ \rowsep +\unicode{0009}{character tabulation} & +\tcode{\textbackslash t} +\\ \rowsep +% +\unicode{000a}{line feed} & +\tcode{\textbackslash n} +\\ \rowsep +% +\unicode{000d}{carriage return} & +\tcode{\textbackslash r} +\\ \rowsep +% +\unicode{0022}{quotation mark} & +\tcode{\textbackslash "} +\\ \rowsep +% +\unicode{005c}{reverse solidus} & +\tcode{\textbackslash\textbackslash} +\\ +\end{floattable} + +\pnum +The escaped string representation of a character \placeholder{C} +is equivalent to the escaped string representation +of a string of \placeholder{C}, except that: + +\begin{itemize} +\item +the result starts and ends with \unicode{0027}{apostrophe} (\tcode{'}) +instead of \unicode{0022}{quotation mark} (\tcode{"}), and +\item +if \placeholder{C} is \unicode{0027}{apostrophe}, +the two characters \tcode{\textbackslash '} are appended to \placeholder{E}, and +\item +if \placeholder{C} is \unicode{0022}{quotation mark}, +then \placeholder{C} is appended unchanged. +\end{itemize} + +%% FIXME: Example is incomplete; s2 and s6 are missing below; +%% FIXME: their Unicode characters are not available in our font (Latin Modern). +\begin{example} +\begin{codeblock} +string s0 = format("[{}]", "h\tllo"); // \tcode{s0} has value: \tcode{[h llo]} +string s1 = format("[{:?}]", "h\tllo"); // \tcode{s1} has value: \tcode{["h\textbackslash tllo"]} +string s3 = format("[{:?}, {:?}]", '\'', '"'); // \tcode{s3} has value: \tcode{['\textbackslash '', '"']} + +// The following examples assume use of the UTF-8 encoding +string s4 = format("[{:?}]", string("\0 \n \t \x02 \x1b", 9)); + // \tcode{s4} has value: \tcode{["\textbackslash u\{0\} \textbackslash n \textbackslash t \textbackslash u\{2\} \textbackslash u\{1b\}"]} +string s5 = format("[{:?}]", "\xc3\x28"); // invalid UTF-8 + // \tcode{s5} has value: \tcode{["\textbackslash x\{c3\}\textbackslash x\{28\}"]} +\end{codeblock} +\end{example} + \rSec3[format.parse.ctx]{Class template \tcode{basic_format_parse_context}} \indexlibraryglobal{basic_format_parse_context}% @@ -15053,17 +15679,600 @@ \end{codeblock} \end{example} -\rSec2[format.arguments]{Arguments} +\rSec2[format.range]{Formatting of ranges} -\rSec3[format.arg]{Class template \tcode{basic_format_arg}} +\rSec3[format.range.fmtkind]{Variable template \tcode{format_kind}} -\indexlibraryglobal{basic_format_arg}% -\begin{codeblock} -namespace std { - template - class basic_format_arg { - public: - class handle; +\indexlibraryglobal{format_kind} +\begin{itemdecl} +template + requires @\libconcept{same_as}@> + constexpr range_format format_kind = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +A program that instantiates the primary template of \tcode{format_kind} +is ill-formed. + +\pnum +For a type \tcode{R}, \tcode{format_kind} is defined as follows: +\begin{itemize} +\item +If \tcode{\libconcept{same_as}>, R>} +is \tcode{true}, +\tcode{format_kind} is \tcode{range_format::disabled}. +\begin{note} +This prevents constraint recursion for ranges whose +reference type is the same range type. +For example, +\tcode{std::filesystem::path} is a range of \tcode{std::filesystem::path}. +\end{note} + +\item +Otherwise, if the \grammarterm{qualified-id} \tcode{R::key_type} +is valid and denotes a type: +\begin{itemize} +\item +If the \grammarterm{qualified-id} \tcode{R::mapped_type} +is valid and denotes a type, +let \tcode{U} be \tcode{remove_cvref_t>}. +If either \tcode{U} is a specialization of \tcode{pair} or +\tcode{U} is a specialization of \tcode{tuple} and +\tcode{tuple_size_v == 2}, +\tcode{format_kind} is \tcode{range_format::map}. +\item +Otherwise, \tcode{format_kind} is \tcode{range_format::set}. +\end{itemize} + +\item +Otherwise, \tcode{format_kind} is \tcode{range_format::sequence}. +\end{itemize} + +\pnum +\remarks +Pursuant to \ref{namespace.std}, users may specialize \tcode{format_kind} +for cv-unqualified program-defined types +that model \tcode{ranges::\libconcept{input_range}}. +Such specializations shall be usable in constant expressions\iref{expr.const} +and have type \tcode{const range_format}. +\end{itemdescr} + +\rSec3[format.range.formatter]{Class template \tcode{range_formatter}} + +\indexlibraryglobal{range_formatter}% +\begin{codeblock} +namespace std { + template + requires @\libconcept{same_as}@, T> && @\libconcept{formattable}@ + class range_formatter { + formatter @\exposid{underlying_}@; // \expos + basic_string_view @\exposid{separator_}@ = @\exposid{STATICALLY-WIDEN}@(", "); // \expos + basic_string_view @\exposid{opening-bracket_}@ = @\exposid{STATICALLY-WIDEN}@("["); // \expos + basic_string_view @\exposid{closing-bracket_}@ = @\exposid{STATICALLY-WIDEN}@("]"); // \expos + + public: + constexpr void set_separator(basic_string_view sep); + constexpr void set_brackets(basic_string_view opening, + basic_string_view closing); + constexpr formatter& underlying() { return @\exposid{underlying_}@; } + constexpr const formatter& underlying() const { return @\exposid{underlying_}@; } + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + requires @\libconcept{formattable}@, charT> && + @\libconcept{same_as}@>, T> + typename FormatContext::iterator + format(R&& r, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\pnum +The class template \tcode{range_formatter} is a utility +for implementing \tcode{formatter} specializations for range types. + +\pnum +\tcode{range_formatter} interprets \fmtgrammarterm{format-spec} +as a \fmtgrammarterm{range-format-spec}. +The syntax of format specifications is as follows: + +\begin{ncbnf} +\fmtnontermdef{range-format-spec}\br + \opt{range-fill-and-align} \opt{width} \opt{\terminal{n}} \opt{range-type} \opt{range-underlying-spec} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{range-fill-and-align}\br + \opt{range-fill} align +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{range-fill}\br + \textnormal{any character other than} \terminal{\{} \textnormal{or} \terminal{\}} \textnormal{or} \terminal{:} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{range-type}\br + \terminal{m}\br + \terminal{s}\br + \terminal{?s} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{range-underlying-spec}\br + \terminal{:} format-spec +\end{ncbnf} + +\pnum +For \tcode{range_formatter}, +the \fmtgrammarterm{format-spec} +in a \fmtgrammarterm{range-underlying-spec}, if any, +is interpreted by \tcode{formatter}. + +\pnum +The \fmtgrammarterm{range-fill-and-align} is interpreted +the same way as a \fmtgrammarterm{fill-and-align}\iref{format.string.std}. +The productions \fmtgrammarterm{align} and \fmtgrammarterm{width} +are described in \ref{format.string}. + +\pnum +The \tcode{n} option causes the range to be formatted +without the opening and closing brackets. +\begin{note} +This is equivalent to invoking \tcode{set_brackets(\{\}, \{\})}. +\end{note} + +\pnum +The \fmtgrammarterm{range-type} specifier changes the way a range is formatted, +with certain options only valid with certain argument types. +The meaning of the various type options +is as specified in \tref{formatter.range.type}. + +\begin{concepttable}{Meaning of \fmtgrammarterm{range-type} options}{formatter.range.type} +{p{1in}p{1.4in}p{2.7in}} +\topline +\hdstyle{Option} & \hdstyle{Requirements} & \hdstyle{Meaning} \\ \capsep +% +\tcode{m} & +\tcode{T} shall be +either a specialization of \tcode{pair} or a specialization of \tcode{tuple} +such that \tcode{tuple_size_v} is \tcode{2}. & +Indicates that +the opening bracket should be \tcode{"\{"}, +the closing bracket should be \tcode{"\}"}, +the separator should be \tcode{", "}, and +each range element should be formatted as if +\tcode{m} were specified for its \fmtgrammarterm{tuple-type}. +\begin{tailnote} +If the \tcode{n} option is provided in addition to the \tcode{m} option, +both the opening and closing brackets are still empty. +\end{tailnote} +\\ \rowsep +% +\tcode{s} & +\tcode{T} shall be \tcode{charT}. & +Indicates that the range should be formatted as a \tcode{string}. +\\ \rowsep +% +\tcode{?s} & +\tcode{T} shall be \tcode{charT}. & +Indicates that the range should be formatted as +an escaped string\iref{format.string.escaped}. +\\ +\end{concepttable} + +If the \fmtgrammarterm{range-type} is \tcode{s} or \tcode{?s}, +then there shall be +no \tcode{n} option and no \fmtgrammarterm{range-underlying-spec}. + +\indexlibrarymember{set_separator}{range_formatter}% +\begin{itemdecl} +constexpr void set_separator(basic_string_view sep); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{\exposid{separator_} = sep;} +\end{itemdescr} + +\indexlibrarymember{set_brackets}{range_formatter}% +\begin{itemdecl} +constexpr void set_brackets(basic_string_view opening, basic_string_view closing); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{opening-bracket_}@ = opening; +@\exposid{closing-bracket_}@ = closing; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{parse}{range_formatter}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Parses the format specifier as a \fmtgrammarterm{range-format-spec} and +stores the parsed specifiers in \tcode{*this}. +The values of +\exposid{opening-bracket_}, \exposid{closing-bracket_}, and \exposid{separator_} +are modified if and only if required by +the \fmtgrammarterm{range-type} or the \tcode{n} option, if present. +If: +\begin{itemize} +\item +the \fmtgrammarterm{range-type} is neither \tcode{s} nor \tcode{?s}, +\item +\tcode{\exposid{underlying_}.set_debug_format()} is a valid expression, and +\item +there is no \fmtgrammarterm{range-underlying-spec}, +\end{itemize} +then calls \tcode{\exposid{underlying_}.set_debug_format()}. + +\pnum +\returns +An iterator past the end of the \fmtgrammarterm{range-format-spec}. +\end{itemdescr} + +\indexlibrarymember{format}{range_formatter}% +\begin{itemdecl} +template + requires @\libconcept{formattable}@, charT> && + @\libconcept{same_as}@>, T> + typename FormatContext::iterator + format(R&& r, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Writes the following into \tcode{ctx.out()}, +adjusted according to the \fmtgrammarterm{range-format-spec}: + +\begin{itemize} +\item +If the \fmtgrammarterm{range-type} was \tcode{s}, +then as if by formatting \tcode{basic_string(from_range, r)}. +\item +Otherwise, if the \fmtgrammarterm{range-type} was \tcode{?s}, +then as if by formatting \tcode{basic_string(from_range, r)} +as an escaped string\iref{format.string.escaped}. +\item +Otherwise, +\begin{itemize} +\item +\exposid{opening-bracket_}, +\item +for each element \tcode{e} of the range \tcode{r}: +\begin{itemize} +\item +the result of writing \tcode{e} via \exposid{underlying_} and +\item +\exposid{separator_}, unless \tcode{e} is the last element of \tcode{r}, and +\end{itemize} +\item +\exposid{closing-bracket_}. +\end{itemize} +\end{itemize} + +\pnum +\returns +An iterator past the end of the output range. +\end{itemdescr} + +\rSec3[format.range.fmtdef]{Class template \exposid{range-default-formatter}} + +\indexlibraryglobal{\exposid{range-default-formatter}}% +\begin{codeblock} +namespace std { + template + struct @\exposidnc{range-default-formatter}@ { // \expos + private: + using @\exposidnc{maybe-const-r}@ = @\exposidnc{fmt-maybe-const}@; // \expos + range_formatter>, + charT> @\exposid{underlying_}@; // \expos + + public: + constexpr void set_separator(basic_string_view sep); + constexpr void set_brackets(basic_string_view opening, + basic_string_view closing); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(@\exposid{maybe-const-r}@& elems, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\indexlibrarymember{set_separator}{\exposid{range-default-formatter}}% +\begin{itemdecl} +constexpr void set_separator(basic_string_view sep); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{\exposid{underlying_}.set_separator(sep);} +\end{itemdescr} + +\indexlibrarymember{set_brackets}{\exposid{range-default-formatter}}% +\begin{itemdecl} +constexpr void set_brackets(basic_string_view opening, basic_string_view closing); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{\exposid{underlying_}.set_brackets(opening, closing);} +\end{itemdescr} + +\indexlibrarymember{parse}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +\end{itemdescr} + +\indexlibrarymember{format}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(@\exposid{maybe-const-r}@& elems, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.format(elems, ctx);} +\end{itemdescr} + +\rSec3[format.range.fmtmap]{Specialization of \exposid{range-default-formatter} for maps} + +\indexlibraryglobal{\exposid{range-default-formatter}}% +\begin{codeblock} +namespace std { + template + struct @\exposid{range-default-formatter}@ { + private: + using @\exposidnc{maybe-const-map}@ = @\exposidnc{fmt-maybe-const}@; // \expos + using @\exposidnc{element-type}@ = // \expos + remove_cvref_t>; + range_formatter<@\exposidnc{element-type}@, charT> @\exposid{underlying_}@; // \expos + public: + constexpr @\exposid{range-default-formatter}@(); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(@\exposid{maybe-const-map}@& r, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\indexlibraryctor{\exposid{range-default-formatter}}% +\begin{itemdecl} +constexpr @\exposid{range-default-formatter}@(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +Either: +\begin{itemize} +\item +\exposid{element-type} is a specialization of \tcode{pair}, or +\item +\exposid{element-type} is a specialization of \tcode{tuple} and +\tcode{tuple_size_v == 2}. +\end{itemize} + +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{underlying_}@.set_brackets(@\exposid{STATICALLY-WIDEN}@("{"), @\exposid{STATICALLY-WIDEN}@("}")); +@\exposid{underlying_}@.underlying().set_brackets({}, {}); +@\exposid{underlying_}@.underlying().set_separator(@\exposid{STATICALLY-WIDEN}@(": ")); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{parse}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +\end{itemdescr} + +\indexlibrarymember{format}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(@\exposid{maybe-const-map}@& r, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.format(r, ctx);} +\end{itemdescr} + +\rSec3[format.range.fmtset]{Specialization of \exposid{range-default-formatter} for sets} + +\indexlibraryglobal{\exposid{range-default-formatter}}% +\begin{codeblock} +namespace std { + template + struct @\exposid{range-default-formatter}@ { + private: + using @\exposidnc{maybe-const-set}@ = @\exposidnc{fmt-maybe-const}@; // \expos + range_formatter>, + charT> @\exposid{underlying_}@; // \expos + + public: + constexpr @\exposid{range-default-formatter}@(); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(@\exposid{maybe-const-set}@& r, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\indexlibraryctor{\exposid{range-default-formatter}}% +\begin{itemdecl} +constexpr @\exposid{range-default-formatter}@(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{underlying_}@.set_brackets(@\exposid{STATICALLY-WIDEN}@("{"), @\exposid{STATICALLY-WIDEN}@("}")); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{parse}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.parse(ctx);} +\end{itemdescr} + +\indexlibrarymember{format}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(@\exposid{maybe-const-set}@& r, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return \exposid{underlying_}.format(r, ctx);} +\end{itemdescr} + +\rSec3[format.range.fmtstr]{Specialization of \exposid{range-default-formatter} for strings} + +\indexlibraryglobal{\exposid{range-default-formatter}}% +\begin{codeblock} +namespace std { + template + requires (K == range_format::string || K == range_format::debug_string) + struct @\exposid{range-default-formatter}@ { + private: + formatter, charT> @\exposid{underlying_}@; // \expos + + public: + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(@\seebelow@& str, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\pnum +\mandates +\tcode{\libconcept{same_as}>, charT>} +is \tcode{true}. + +\indexlibrarymember{parse}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +auto i = @\exposid{underlying_}@.parse(ctx); +if constexpr (K == range_format::debug_string) { + @\exposid{underlying_}@.set_debug_format(); +} +return i; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{format}{\exposid{range-default-formatter}}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(@\seebelow@& r, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The type of \tcode{r} is \tcode{const R\&} +if \tcode{ranges::\libconcept{input_range}} is \tcode{true} and +\tcode{R\&} otherwise. + +\pnum +\effects +Let \tcode{\placeholder{s}} be a \tcode{basic_string} such that +\tcode{ranges::equal(\placeholder{s}, r)} is \tcode{true}. +Equivalent to: \tcode{return \exposid{underlying_}.format(\placeholder{s}, ctx);} +\end{itemdescr} + +\rSec2[format.arguments]{Arguments} + +\rSec3[format.arg]{Class template \tcode{basic_format_arg}} + +\indexlibraryglobal{basic_format_arg}% +\begin{codeblock} +namespace std { + template + class basic_format_arg { + public: + class handle; private: using char_type = typename Context::char_type; // \expos @@ -15471,6 +16680,200 @@ \tcode{i < size_ ?\ data_[i] :\ basic_format_arg()}. \end{itemdescr} +\rSec2[format.tuple]{Tuple formatter} + +\pnum +For each of \tcode{pair} and \tcode{tuple}, +the library provides the following formatter specialization +where \tcode{\placeholder{pair-or-tuple}} is the name of the template: + +\indexlibraryglobal{formatter}% +\begin{codeblock} +namespace std { + template... Ts> + struct formatter<@\placeholder{pair-or-tuple}@, charT> { + private: + tuple, charT>...> @\exposid{underlying_}@; // \expos + basic_string_view @\exposid{separator_}@ = @\exposid{STATICALLY-WIDEN}@(", "); // \expos + basic_string_view @\exposid{opening-bracket_}@ = @\exposid{STATICALLY-WIDEN}@("("); // \expos + basic_string_view @\exposid{closing-bracket_}@ = @\exposid{STATICALLY-WIDEN}@(")"); // \expos + + public: + constexpr void set_separator(basic_string_view sep); + constexpr void set_brackets(basic_string_view opening, + basic_string_view closing); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(@\seebelow@& elems, FormatContext& ctx) const; + }; +} +\end{codeblock} + +\pnum +The \tcode{parse} member functions of these formatters +interpret the format specification as +a \fmtgrammarterm{tuple-format-spec} according to the following syntax: + +\begin{ncbnf} +\fmtnontermdef{tuple-format-spec}\br + \opt{tuple-fill-and-align} \opt{width} \opt{tuple-type} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{tuple-fill-and-align}\br + \opt{tuple-fill} align +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{tuple-fill}\br + \textnormal{any character other than} \terminal{\{} \textnormal{or} \terminal{\}} \textnormal{or} \terminal{:} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{tuple-type}\br + \terminal{m}\br + \terminal{n} +\end{ncbnf} + +\pnum +The \fmtgrammarterm{tuple-fill-and-align} is interpreted the same way as +a \fmtgrammarterm{fill-and-align}\iref{format.string.std}. +The productions \fmtgrammarterm{align} and \fmtgrammarterm{width} +are described in \ref{format.string}. + +\pnum +The \fmtgrammarterm{tuple-type} specifier +changes the way a \tcode{pair} or \tcode{tuple} is formatted, +with certain options only valid with certain argument types. +The meaning of the various type options +is as specified in \tref{formatter.tuple.type}. + +\begin{concepttable}{Meaning of \fmtgrammarterm{tuple-type} options}{formatter.tuple.type} +{p{0.5in}p{1.4in}p{3.2in}} +\topline +\hdstyle{Option} & \hdstyle{Requirements} & \hdstyle{Meaning} \\ \capsep +% +\tcode{m} & +\tcode{sizeof...(Ts) == 2} & +Equivalent to: +\begin{codeblock} +set_separator(@\exposid{STATICALLY-WIDEN}@(": ")); +set_brackets({}, {}); +\end{codeblock}% +\\ \rowsep +% +\tcode{n} & +none & +Equivalent to: \tcode{set_brackets(\{\}, \{\});} +\\ \rowsep +% +none & +none & +No effects +\\ +\end{concepttable} + +\indexlibrarymember{set_separator}{formatter}% +\begin{itemdecl} +constexpr void set_separator(basic_string_view sep); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{\exposid{separator_} = sep;} +\end{itemdescr} + +\indexlibrarymember{set_brackets}{formatter}% +\begin{itemdecl} +constexpr void set_brackets(basic_string_view opening, basic_string_view closing); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +@\exposid{opening-bracket_}@ = opening; +@\exposid{closing-bracket_}@ = closing; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{parse}{formatter}% +\begin{itemdecl} +template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Parses the format specifier as a \fmtgrammarterm{tuple-format-spec} and +stores the parsed specifiers in \tcode{*this}. +The values of +\exposid{opening-bracket_}, +\exposid{closing-bracket_}, and +\exposid{separator_} +are modified if and only if +required by the \fmtgrammarterm{tuple-type}, if present. +For each element \tcode{\placeholder{e}} in \exposid{underlying_}, +if \tcode{\placeholder{e}.set_debug_format()} is a valid expression, +calls \tcode{\placeholder{e}.set_debug_format()}. + +\pnum +\returns +An iterator past the end of the \fmtgrammarterm{tuple-format-spec}. +\end{itemdescr} + +\indexlibrarymember{format}{formatter}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(@\seebelow@& elems, FormatContext& ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The type of \tcode{elems} is: +\begin{itemize} +\item +If \tcode{(\libconcept{formattable} \&\& ...)} is \tcode{true}, +\tcode{const \placeholder{pair-or-tuple}\&}. +\item +Otherwise \tcode{\placeholder{pair-or-tuple}\&}. +\end{itemize} + +\pnum +\effects +Writes the following into \tcode{ctx.out()}, +adjusted according to the \fmtgrammarterm{tuple-format-spec}: +\begin{itemize} +\item +\exposid{opening-bracket_}, +\item +for each index \tcode{I} in the \range{0}{sizeof...(Ts)}: +\begin{itemize} +\item +if \tcode{I != 0}, \exposid{separator_}, +\item +the result of writing \tcode{get(elems)} +via \tcode{get(\exposid{underlying_})}, and +\end{itemize} +\item +\exposid{closing-bracket_}. +\end{itemize} + +\pnum +\returns +An iterator past the end of the output range. +\end{itemdescr} + \rSec2[format.error]{Class \tcode{format_error}} \indexlibraryglobal{format_error}% @@ -15521,6 +16924,7 @@ \rSec2[bit.syn]{Header \tcode{} synopsis} \begin{codeblock} +// all freestanding namespace std { // \ref{bit.cast}, \tcode{bit_cast} template @@ -15538,7 +16942,7 @@ template constexpr T bit_floor(T x) noexcept; template - constexpr T bit_width(T x) noexcept; + constexpr int bit_width(T x) noexcept; // \ref{bit.rotate}, rotating template @@ -15722,7 +17126,7 @@ \indexlibraryglobal{bit_width}% \begin{itemdecl} template - constexpr T bit_width(T x) noexcept; + constexpr int bit_width(T x) noexcept; \end{itemdecl} \begin{itemdescr} diff --git a/source/xrefdelta.tex b/source/xrefdelta.tex index 719ca93f9c..f81f0a2eef 100644 --- a/source/xrefdelta.tex +++ b/source/xrefdelta.tex @@ -62,7 +62,9 @@ \movedxref{fs.req.general}{fs.req} % P2325R3 Views should not be required to be default constructible -\movedxref{range.semi.wrap}{range.copy.wrap} +% P2494R2 Relaxing range adaptors to allow for move only types +% range.semi.wrap => range.copy.wrap => range.move.wrap +\movedxref{range.semi.wrap}{range.move.wrap} % P2210R2 Superior String Splitting \movedxref{range.split.outer}{range.lazy.split.outer} @@ -96,5 +98,11 @@ \movedxref{defns.direct-non-list-init}{defns.direct.non.list.init} \movedxref{defns.expression-equivalent}{defns.expression.equivalent} +% P1467R9 Extended floating-point types and standard names +\movedxref{complex.special}{complex.members} + +% LWG3659 Consider ATOMIC_FLAG_INIT undeprecation +\removedxref{depr.atomics.flag} + % Deprecated features. %\deprxref{old.label} (if moved to depr.old.label, otherwise use \movedxref) diff --git a/tools/check-output.sh b/tools/check-output.sh index 257ec2fd63..206e2b4f98 100755 --- a/tools/check-output.sh +++ b/tools/check-output.sh @@ -48,6 +48,30 @@ cat std-grammarindex.ind | sed 's/^\(.*\)$/grammar non-terminal \1 has no definition/' | fail || failed=1 +# Find concept index entries missing a definition +cat std-conceptindex.ind | + sed 's/.hyperindexformat/\nhyperindexformat/;s/.hyperpage/hyperpage/' | + awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } item=$NF; def=0; next } /hyperindexformat/ { def=1 }' | + sed 's/^\(.*\)$/concept \1 has no definition/' | + fail || failed=1 + +# Find undecorated concept names in code blocks +patt="`cat std-conceptindex.ind | + sed 's/.hyperindexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/' | + sed -n 's/^ .item.*{\([-a-z_]*\)}.*$/\1/p'`" + +patt="`echo $patt | sed 's/ /\\\\|/g'`" +# $patt contains all concept names, separated by \| to use as a sed regex + +for f in *.tex; do + sed -n 's,//.*$,,;s/%.*$//;s/"[^"]*"/""/;/begin{codeblock\(tu\)\?}/,/end{codeblock\(tu\)\?}/{/[^-_{a-z\]\('"$patt"'\)[^-_}a-z();]/{=;p;};}' $f | + # prefix output with filename and line + sed '/^[0-9]\+$/{N;s/\n/:/;}' | sed "s/.*/$f:&/" | + grep -v "@.seebelow" | + sed "s/\$/ -- concept name without markup/" | + fail || failed=1 +done + # Cross references since the previous standard. function indexentries() { sed 's,\\glossaryentry{\(.*\)@.*,\1,' "$1" | LANG=C sort; } function removals() { diff -u "$1" "$2" | grep '^-' | grep -v '^---' | sed 's/^-//'; } diff --git a/tools/check-source.sh b/tools/check-source.sh index 6d53272b64..db5291587d 100755 --- a/tools/check-source.sh +++ b/tools/check-source.sh @@ -108,9 +108,9 @@ grep -Hne '^\\\(change\|rationale\|effect\|difficulty\|howwide\)\s.\+$' compatib fail "change marker in [diff] followed by stuff" || failed=1 # Fixup: sed 's/^\\\(change\|rationale\|effect\|difficulty\|howwide\)\s\(.\)/\\\1\n\2/'q -# "template - + + + \n$(echo -n "${paper}" | tr prn PRN)\n\n" markdown "${1}" + +echo -e "\n" ) > "${paper}.html"