diff --git a/docs/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions.md b/docs/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions.md index 13df59084e6..361c713b021 100644 --- a/docs/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions.md +++ b/docs/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions.md @@ -33,7 +33,7 @@ A basic conversion specification contains only the percent sign and a *type* cha The *type* conversion specifier character specifies whether to interpret the corresponding argument as a character, a string, a pointer, an integer, or a floating-point number. The *type* character is the only required conversion specification field, and it appears after any optional fields. -The arguments that follow the format string are interpreted according to the corresponding *type* character and the optional [*size*](#size) prefix. Conversions for character types `char` and `wchar_t` are specified by using **`c`** or **`C`**, and single-byte and multi-byte or wide character strings are specified by using **`s`** or **`S`**, depending on which formatting function is being used. Character and string arguments that are specified by using **`c`** and **`s`** are interpreted as `char` and `char*` by `printf` family functions, or as `wchar_t` and `wchar_t*` by `wprintf` family functions. Character and string arguments that are specified by using **`C`** and **`S`** are interpreted as `wchar_t` and `wchar_t*` by `printf` family functions, or as `char` and `char*` by `wprintf` family functions. This behavior is Microsoft-specific. +The arguments that follow the format string are interpreted according to the corresponding *type* character and the optional [*size*](#size) prefix. Conversions for character types `char` and `wchar_t` are specified by using **`c`** or **`C`**, and single-byte and multi-byte or wide character strings are specified by using **`s`** or **`S`**, depending on which formatting function is being used. Character and string arguments that are specified by using **`c`** and **`s`** are interpreted as `char` and `char*` by `printf` family functions, or as `wchar_t` and `wchar_t*` by `wprintf` family functions. Character and string arguments that are specified by using **`C`** and **`S`** are interpreted as `wchar_t` and `wchar_t*` by `printf` family functions, or as `char` and `char*` by `wprintf` family functions. This behavior is Microsoft-specific. For historical reasons, the `wprintf` functions use **`c`** and **`s`** to refer to `wchar_t` characters, and **`C`** and **`S`** specify narrow characters. Integer types such as `short`, `int`, `long`, `long long`, and their `unsigned` variants, are specified by using **`d`**, **`i`**, **`o`**, **`u`**, **`x`**, and **`X`**. Floating-point types such as `float`, `double`, and `long double`, are specified by using **`a`**, **`A`**, **`e`**, **`E`**, **`f`**, **`F`**, **`g`**, and **`G`**. By default, unless they're modified by a *size* prefix, integer arguments are coerced to `int` type, and floating-point arguments are coerced to `double`. On 64-bit systems, an `int` is a 32-bit value; so, 64-bit integers will be truncated when they're formatted for output unless a *size* prefix of **`ll`** or **`I64`** is used. Pointer types that are specified by **`p`** use the default pointer size for the platform. diff --git a/docs/c-runtime-library/reference/asctime-wasctime.md b/docs/c-runtime-library/reference/asctime-wasctime.md index dc1910477b1..f08c1fbfb8e 100644 --- a/docs/c-runtime-library/reference/asctime-wasctime.md +++ b/docs/c-runtime-library/reference/asctime-wasctime.md @@ -1,7 +1,7 @@ --- description: "Learn more about: asctime, _wasctime" title: "asctime, _wasctime" -ms.date: "4/2/2020" +ms.date: 12/21/2022 api_name: ["_wasctime", "asctime", "_o__wasctime", "_o_asctime"] api_location: ["msvcrt.dll", "msvcr80.dll", "msvcr90.dll", "msvcr100.dll", "msvcr100_clr0400.dll", "msvcr110.dll", "msvcr110_clr0400.dll", "msvcr120.dll", "msvcr120_clr0400.dll", "ucrtbase.dll", "api-ms-win-crt-time-l1-1-0.dll"] api_type: ["DLLExport"] @@ -52,11 +52,11 @@ The **`asctime`** function converts a time stored as a structure to a character | `tm_yday` | Day of year (0-365; January 1 = 0) | | `tm_year` | Year (current year minus 1900) | -The converted character string is also adjusted according to the local time zone settings. For information about configuring the local time, see the [`time`](time-time32-time64.md), [`_ftime`](ftime-ftime32-ftime64.md), and [`localtime`](localtime-localtime32-localtime64.md) functions. For information about defining the time zone environment and global variables, see the [`_tzset`](tzset.md) function. +For information about configuring the local time, see the [`time`](time-time32-time64.md), [`_ftime`](ftime-ftime32-ftime64.md), and [`localtime`](localtime-localtime32-localtime64.md) functions. For information about defining the time zone environment and global variables, see the [`_tzset`](tzset.md) function. The string result produced by **`asctime`** contains exactly 26 characters and has the form `Wed Jan 2 02:03:55 1980\n\0`. A 24-hour clock is used. All fields have a constant width. The newline character and the null character occupy the last two positions of the string. **`asctime`** uses a single, statically allocated buffer to hold the return string. Each call to this function destroys the result of the previous call. -**`_wasctime`** is a wide-character version of **`asctime`**. **`_wasctime`** and **`asctime`** behave identically otherwise. +**`_wasctime`** is a wide-character version of **`asctime`**, and otherwise behaves identically to **`asctime`**. These functions validate their parameters. If *`timeptr`* is a null pointer, or if it contains out-of-range values, the invalid parameter handler is invoked, as described in [Parameter validation](../parameter-validation.md). If execution is allowed to continue, the function returns `NULL` and sets `errno` to `EINVAL`. @@ -64,7 +64,7 @@ By default, this function's global state is scoped to the application. To change ### Generic-text routine mapping -| TCHAR.H routine | `_UNICODE` and `_MBCS` not defined | `_MBCS` defined | `_UNICODE` defined | +| `TCHAR.H` routine | `_UNICODE` and `_MBCS` not defined | `_MBCS` defined | `_UNICODE` defined | |---|---|---|---| | `_tasctime` | **`asctime`** | **`asctime`** | **`_wasctime`** | @@ -72,12 +72,12 @@ By default, this function's global state is scoped to the application. To change | Routine | Required header | |---|---| -| **`asctime`** | \ | -| **`_wasctime`** | \ or \ | +| **`asctime`** | `` | +| **`_wasctime`** | `` or `` | ## Example -This program places the system time in the long integer `aclock`, translates it into the structure `newtime` and then converts it to string form for output, using the **`asctime`** function. +This program places the system time in the long integer `aclock`, translates it into the structure `newtime`, and then converts it to string form for output using the **`asctime`** function. ```C // crt_asctime.c diff --git a/docs/c-runtime-library/reference/fopen-wfopen.md b/docs/c-runtime-library/reference/fopen-wfopen.md index 38c307eae93..2a7036a39ae 100644 --- a/docs/c-runtime-library/reference/fopen-wfopen.md +++ b/docs/c-runtime-library/reference/fopen-wfopen.md @@ -8,7 +8,6 @@ api_type: ["DLLExport"] topic_type: ["apiref"] f1_keywords: ["STDIO/fopen", "CORECRT_WSTDIO/_wfopen", "TCHAR/_tfopen", "fopen", "_wfopen", "_tfopen"] helpviewer_keywords: ["opening files, for file I/O", "wfopen function", "tfopen function", "_tfopen function", "_wfopen function", "files [C++], opening", "fopen function"] -ms.assetid: e868993f-738c-4920-b5e4-d8f2f41f933d --- # `fopen`, `_wfopen` @@ -70,7 +69,7 @@ The following table summarizes the modes that are used for various **`ccs`** fla ### Encodings used based on ccs flag and BOM -| ccs flag | No BOM (or new file) | BOM: UTF-8 | BOM: UTF-16 | +| `ccs` flag | No BOM (or new file) | BOM: UTF-8 | BOM: UTF-16 | |--|--|--|--| | `UNICODE` | **`UTF-16LE`** | **`UTF-8`** | **`UTF-16LE`** | | **`UTF-8`** | **`UTF-8`** | **`UTF-8`** | **`UTF-16LE`** | @@ -82,7 +81,7 @@ If *`mode`* is **`a, ccs=encoding`** for some `encoding` value, **`fopen`** firs ### Generic-text routine mappings -| TCHAR.H routine | `_UNICODE` and `_MBCS` not defined | `_MBCS` defined | `_UNICODE` defined | +| `TCHAR.H` routine | `_UNICODE` and `_MBCS` not defined | `_MBCS` defined | `_UNICODE` defined | |--|--|--|--| | **`_tfopen`** | **`fopen`** | **`fopen`** | **`_wfopen`** | @@ -130,7 +129,7 @@ The following options can be appended to *`mode`* to specify more behaviors. | **`R`** | Specifies that caching is optimized for, but not restricted to, random access from disk. | | **`T`** | Specifies a file as temporary. If possible, it isn't flushed to disk. | | **`D`** | Specifies a file as temporary. It's deleted when the last file pointer is closed. | -| **`ccs=encoding`** | Specifies the encoded character set to use (one of **`UTF-8`**, **`UTF-16LE`**, or `UNICODE`) for this file. Leave unspecified if you want ANSI encoding. | +| **`ccs=encoding`** | Specifies the encoded character set to use (one of **`UTF-8`**, **`UTF-16LE`**, or `UNICODE`) for this file. Leave unspecified if you want ANSI encoding. This flag is separated from flags that precede it by a comma (`,`). For example: `FILE *f = fopen("newfile.txt", "rt+, ccs=UTF-8");` | Valid characters for the *`mode`* string that is used in **`fopen`** and **`_fdopen`** correspond to *`oflag`* arguments that are used in [`_open`](open-wopen.md) and [`_sopen`](sopen-wsopen.md), as follows. diff --git a/docs/overview/cpp-conformance-improvements-2019.md b/docs/overview/cpp-conformance-improvements-2019.md index dd545856d13..22857890443 100644 --- a/docs/overview/cpp-conformance-improvements-2019.md +++ b/docs/overview/cpp-conformance-improvements-2019.md @@ -66,7 +66,16 @@ To avoid the errors, insert a space in the offending line before the final angle ### References to types with mismatched cv-qualifiers -Previously, MSVC allowed direct binding of a reference from a type with mismatched cv-qualifiers below the top level. This binding could allow modification of supposedly const data referred to by the reference. The compiler now creates a temporary, as required by the standard. In Visual Studio 2017, the following code compiles without warnings. In Visual Studio 2019, the compiler raises warning C4172: +>[!Note] +> This change only affects Visual Studio 2019 versions 16.0 through 16.8. It was reverted starting in Visual Studio 2019 version 16.9 + +Previously, MSVC allowed direct binding of a reference from a type with mismatched cv-qualifiers below the top level. This binding could allow modification of supposedly const data referred to by the reference. + +The compiler for Visual Studio 2019 versions 16.0 through 16.8 instead creates a temporary, as was required by the standard at that time. Later, the standard retroactively changed making the previous behavior of Visual Studio 2017 and earlier correct, and the behavior of Visual Studio 2019 version 16.0 through 16.8 wrong. Consequently, this change was reverted starting in Visual Studio 2019 version 16.9. + +See [Similar types and reference binding](#similar-types-and-reference-binding) for a related change. + +As an example, in Visual Studio 2017, the following code compiles without warnings. In Visual Studio 2019 versions 16.0 through 16.8, the compiler raises warning C4172. Starting with Visual Studio 2019 version 16.9, the code once again compiles without warnings: ```cpp struct X @@ -2067,10 +2076,14 @@ With this change, a destructor is also potentially throwing if it has a virtual ### Similar types and reference binding -Core Working Group issue [CWG 2352](https://wg21.link/cwg2352) deals with an inconsistency between the reference binding rules and changes to type similarity. The inconsistency was introduced in earlier Defect Reports (such as [CWG 330](https://wg21.link/cwg330)). With this change, code that previously bound a reference to a temporary may now bind directly when the types involved differ only by cv-qualifiers. +Core Working Group issue [CWG 2352](https://wg21.link/cwg2352) deals with an inconsistency between the reference binding rules and changes to type similarity. The inconsistency was introduced in earlier Defect Reports (such as [CWG 330](https://wg21.link/cwg330)). This affected Visual Studio 2019 versions 16.0 through 16.8. + +With this change, starting in Visual Studio 2019 version 16.9, code that previously bound a reference to a temporary in Visual Studio 2019 version 16.0 throught 16.8 may now bind directly when the types involved differ only by cv-qualifiers. Visual Studio 2019 version 16.9 implements the changed behavior in all **`/std`** compiler modes. It's potentially a source breaking change. +See [References to types with mismatched cv-qualifiers](#references-to-types-with-mismatched-cv-qualifiers) for a related change. + This sample shows the changed behavior: ```cpp diff --git a/docs/standard-library/common-view-class.md b/docs/standard-library/common-view-class.md index a1d17edbf8c..68d3377c8cb 100644 --- a/docs/standard-library/common-view-class.md +++ b/docs/standard-library/common-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::common`](range-adaptors.md#common) | | **Underlying range** | Must satisfy [`forward_range`](range-concepts.md#forward_range) or higher | | **Element type** | Same as the underlying range | -| **View iterator category** | Supports `forward_range` or [`random_access_range`](range-concepts.md#random_access_range) when the underlying range satisfies `random_access_range` and [`sized_range`](range-concepts.md#sized_range) | +| **View iterator category** | `forward_range` or [`random_access_range`](range-concepts.md#random_access_range) when the underlying range satisfies `random_access_range` and [`sized_range`](range-concepts.md#sized_range) | | **Sized** | Only if the underlying range satisfies [`sized_range`](range-concepts.md#sized_range) | | **Is `const`-iterable** | Only if the underlying range is `const` iterable | | **Common range** | Yes | diff --git a/docs/standard-library/drop-while-view-class.md b/docs/standard-library/drop-while-view-class.md index 8538b8a36bf..02f2543e1eb 100644 --- a/docs/standard-library/drop-while-view-class.md +++ b/docs/standard-library/drop-while-view-class.md @@ -36,7 +36,7 @@ For a description of the following entries, see [View class characteristics](vie | Characteristic | Description | |--|--| | **Range adaptor** | [`views::drop_while`](range-adaptors.md#drop_while) | -| **Underlying range** | Must satisfy [`forward_range`](range-concepts.md#forward_range) or higher and the underlying range's iterators must model `sized_sentinel_for` | +| **Underlying range** | Must satisfy [`forward_range`](range-concepts.md#forward_range) or higher and the underlying range's iterators must model [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for) | | **Element type** | Same as the underlying range | | **View iterator category** | Same as the underlying range | | **Sized** | Only if the underlying range satisfies [`random_access_range`](range-concepts.md#random_access_range) | diff --git a/docs/standard-library/empty-view-class.md b/docs/standard-library/empty-view-class.md index 46d162d6b1c..67adb0d220a 100644 --- a/docs/standard-library/empty-view-class.md +++ b/docs/standard-library/empty-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::empty`](range-adaptors.md#empty) | | **Underlying range** | None | | **Element type** | As specified when the `empty_view` is created | -| **View iterator category** | Supports `contiguous_range` | +| **View iterator category** | `contiguous_range` | | **Sized** | Yes. Always returns 0 | | **Is `const`-iterable** | Yes | | **Common range** | Yes | @@ -82,7 +82,7 @@ inline constexpr empty_view empty{}; ### Parameters *`T`*\ - The type of the underlying element, of which there are none. + The type of the underlying element, of which there is none. ### Remarks diff --git a/docs/standard-library/filter-view-class.md b/docs/standard-library/filter-view-class.md index 91c5a0842aa..23cbc042677 100644 --- a/docs/standard-library/filter-view-class.md +++ b/docs/standard-library/filter-view-class.md @@ -35,7 +35,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::filter`](range-adaptors.md#filter) | | **Underlying range** | Must satisfy [`input_range`](range-concepts.md#input_range) or higher | | **Element type** | Same as the underlying range | -| **View iterator category** | Supports `input_range`, [`forward_range`](range-concepts.md#forward_range), or [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range | +| **View iterator category** | `input_range`, [`forward_range`](range-concepts.md#forward_range), or [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range | | **Sized** | No | | **Is `const`-iterable** | No | | **Common range** | Only if the underlying range satisfies [`common_range`](range-concepts.md#common_range) | diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md new file mode 100644 index 00000000000..b26c47b97a4 --- /dev/null +++ b/docs/standard-library/iterator-concepts.md @@ -0,0 +1,484 @@ +--- +description: "Learn more about iterator concepts." +title: "Iterator concepts" +ms.date: 12/16/2022 +f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_iterator", "ranges/std::ranges::borrowed_iterator", "ranges/std::ranges::common_iterator", "ranges/std::ranges::contiguous_iterator", "ranges/std::ranges::forward_iterator", "ranges/std::ranges::input_iterator", "ranges/std::ranges::output_iterator", "ranges/std::ranges::random_access_iterator", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_iterator", "ranges/std::ranges::view", "ranges/std::ranges::viewable_iterator"] +helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_iterator", "std::ranges [C++], ranges::borrowed_iterator", "std::ranges [C++], ranges::common_iterator", "std::ranges [C++], ranges::contiguous_iterator", "std::ranges [C++], ranges::forward_iterator", "std::ranges [C++], ranges::input_iterator", "std::ranges [C++], ranges::output_iterator", "std::ranges [C++], ranges::random_access_iterator", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_iterator", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_iterator"] +--- +# Iterator concepts + +Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. + +Consider the following example, which defines a concept to prevent instantiating the template with a type that doesn't support division: + +```cpp +// requires /std:c++20 or later +#include + +// Definition of dividable concept which requires +// that arguments a & b of type T support division +template +concept dividable = requires (T a, T b) +{ + a / b; +}; + +// Apply the concept to a template. +// The template will only be instantiated if argument T supports division. +// This prevents the template from being instantiated with types that don't support division. +// This could have been applied to the parameter of a template function, but because +// most of the concepts in the library are applied to classes, this form is demonstrated. +template requires dividable +class DivideEmUp +{ +public: + T Divide(T x, T y) + { + return x / y; + } +}; + +int main() +{ + DivideEmUp dividerOfInts; + std::cout << dividerOfInts.Divide(6, 3); // outputs 2 + // The following line will not compile because the template can't be instantiated + // with char* because char* can be divided + DivideEmUp dividerOfCharPtrs; // compiler error: cannot deduce template arguments +} +``` + +When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 version 17.4 preview 4 or later, the error that concept `dividable` evaluated to false will point directly to the expression requirement `(a / b)` that failed. + +Iterator concepts are defined in the `std` namespace, and are declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. + +There are six categories of iterators. They're directly related to the categories of ranges listed under [Range concepts](ranges.md#range-concepts). + +The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. + +:::image type="content" source="media/iterator-hiearchy.svg" alt-text="Diagram of the iterator hierarchy. input_or_output_iterator is the base. input_iterator and output_iterator are shown as refining input_or_output_iterator. forward_iterator is next and refines both input_iterator and output_iterator. bidirectional_iterator refines forward_iterator. random_access_iterator refines bidirectional_iterator. Finally, contiguous_iterator refines random_access_iterator"::: + +In the following table, "Multi-pass" refers to whether the iterator can revisit the same element more than once. For example, `vector::iterator` is a multi-pass iterator because you can make a copy of the iterator, read the elements in the collection, and then restore the iterator to the value in the copy, and revisit the same elements again. If an iterator is single-pass, you can only visit the elements in the collection once. + +In the following table, "Example types" refers to collections/iterators that satisfy the concept. + +| Iterator concept | Description | Direction | Read/write | Multi-pass | Example types | +|--|--|--|--|--|--| +| [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | Forward | Read/write | no | `istream_iterator`, `ostream_iterator` | +| [`output_iterator`](#output_iterator)C++20 | Specifies an iterator that you can write to. | Forward | Write | no | `ostream`, `inserter` | +| [`input_iterator`](#input_iterator)C++20 | Specifies an iterator that you can read from once. | Forward | Read | no | `istream`, `istreambuf_iterator` | +| [`forward_iterator`](#forward_iterator)C++20 | Specifies an iterator that can read (and possibly write) multiple times. | Forward | Read/write | yes | `vector`, `list` | +| [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Specifies an iterator that you can read and write both forwards and backwards. | Forward or backward | Read/write | yes | `list`, `set`, `multiset`, `map`, and `multimap`. | +| [`random_access_iterator`](#random_access_iterator)C++20 | Specifies an iterator that you can read and write by index. | Forward or backward | Read/write | yes | `vector`, `array`, `deque` | +| [`contiguous_iterator`](#contiguous_iterator)C++20 | Specifies an iterator whose elements are sequential in memory, are the same size, and can be accessed using pointer arithmetic. | Forward or backward | Read/write | yes | `array`, `vector` `string`.| + +Other iterator concepts include: + +| Iterator concept | Description | +|--|--| +| [`sentinel_for`](#sentinel_for)C++20 | Specifies that a type is a sentinel for an iterator type. | +| [`sized_sentinel_for`](#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | + +## `bidirectional_iterator` + +A `bidirectional_iterator` supports reading and writing forwards and backwards. + +```cpp +template +concept bidirectional_iterator = + forward_iterator && + derived_from && + requires(I i) { + {--i} -> same_as; + {i--} -> same_as; +}; +``` + +### Parameters + +*`I`*\ +The iterator to test to see if it's a `bidirectional_iterator`. + +### Remarks + +A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. + +Some examples of containers that can be used with a `bidirectional_iterator` are `set`, `multiset`, `map`, `multimap`, `vector`, and `list`. + +### Example: `bidirectional_iterator` + +The following example uses the `bidirectional_iterator` concept to show that `vector` has a `bidirectional_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + std::cout << std::boolalpha << std::bidirectional_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::contiguous_iterator; // outputs true +} +``` + +## `contiguous_iterator` + +Specifies an iterator whose elements are sequential in memory, are the same size, and can be accessed using pointer arithmetic. + +```cpp +template + concept contiguous_iterator = + random_access_iterator && + derived_from && + is_lvalue_reference_v> && + same_as, remove_cvref_t>> && + requires(const I& i) { + { to_address(i) } -> same_as>>; + }; +``` + +### Parameters + +*`I`*\ +The type to test to see if it's a `contiguous_iterator`. + +### Remarks + +A `contiguous_iterator` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. Some examples of a `contiguous_iterator` are `array`, `vector`, and `string`. + +### Example: `contiguous_iterator` + +The following example uses the `contiguous_iterator` concept to show that a `vector` has a `contiguous_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + // Show that vector has a contiguous_iterator + std::cout << std::boolalpha << std::contiguous_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::contiguous_iterator; // outputs true +} +``` + +## `forward_iterator` + +Has the capabilities of an `input_iterator` and an `output_iterator`. Supports iterating over a collection multiple times. + +```cpp +template + concept forward_iterator = + input_iterator && + derived_from && + incrementable && + sentinel_for; +``` + +### Parameters + +*`I`*\ +The iterator to test to see if it's a `forward_iterator`. + +### Remarks + +A `forward_iterator` can only move forward. + +Some examples of containers that can be used with a `forward_iterator` are `vector`, `list`, `unordered_set`, `unordered_multiset`, `unordered_map`, and `unordered_multimap`. + +### Example: `forward_iterator` + +The following example uses the `forward_iterator` concept to show that a `vector` has a `forward_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + // Show that vector has a forward_iterator + std::cout << std::boolalpha << std::forward_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::forward_iterator; // outputs true +} +``` + +## `input_iterator` + +An `input_iterator` is an iterator that you can read from at least once. + +```cpp +template +concept input_iterator = + input_or_output_iterator && + indirectly_readable && + requires { typename ITER_CONCEPT(I); } && + derived_from; +``` + +### Parameters + +*`I`*\ +The type to test to see if it's an `input_iterator`. + +### Remarks + +Calling `begin()` on an `input_iterator` more than once results in undefined behavior. A type that only models `input_iterator` isn't multi-pass. Consider reading from standard input (`cin`) for example. In this case, you can only read the current element once and you can't re-read characters you've already read. An `input_iterator` only reads forward, not backwards. + +### Example: `input_iterator` + +The following example uses the `input_iterator` concept to show that an `istream_iterator` has an `input_iterator`: + +```cpp +// requires /std:c++20 or later +#include + +int main() +{ + // Show that a istream_iterator has an input_iterator + std::cout << std::boolalpha << std::input_iterator>; // outputs true +} +``` + +## `input_or_output_iterator` + +An `input_or_output_iterator` is the basis of the iterator concept taxonomy. It supports dereferencing and incrementing +an iterator. Every iterator models `input_or_output_iterator`. + +```cpp +template +concept input_or_output_iterator = + requires(I i) { + { *i } -> can-reference; + } && + weakly_incrementable; +``` + +### Parameters + +*`I`*\ +The type to test to see if it's an `input_or_output_iterator`. + +### Remarks + +The concept `can-reference` means that the type `I` is a reference, a pointer, or a type that can be implicitly converted to a reference. + +### Example: `input_or_output_iterator` + +The following example uses the `input_or_output_iterator` concept to show that `vector` has an `input_or_output_iterator`: + +```cpp +// requires /std:c++20 or later +#include + +int main() +{ + // Show that a vector has an input_or_output_iterator + std::cout << std::boolalpha << std::input_or_output_iterator::iterator> << '\n'; // outputs true + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::input_or_output_iterator; // outputs true +} +``` + +## `output_iterator` + +An `output_iterator` is an iterator that you can write to. + +```cpp +template +concept output_iterator = + input_or_output_iterator && + indirectly_writable && + requires(I i, T&& t) { + *i++ = std::forward(t); + }; +``` + +### Parameters + +*`I`*\ +The type to test to see if it's an `output_iterator`. + +*`T`*\ +The type of the values to write. + +### Remarks + +An `output_iterator` is single pass. That is, it can only write to the same element once. + +### Example: `output_iterator` + +The following example uses the `output_iterator` concept to show that `vector` has an `output_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + // Show that vector has an output_iterator + std::cout << std::boolalpha << std::output_iterator::iterator, int> << "\n"; // outputs "true" + + // another way to test + std::vector v = {0,1,2,3,4,5}; + std::cout << std::boolalpha << std::output_iterator; // outputs true +} +``` + +## `random_access_iterator` + +A `random_access_iterator` can read or write by index. + +```cpp +template +concept random_access_iterator = + bidirectional_iterator && + derived_from && + totally_ordered && + sized_sentinel_for && + requires(I i, const I j, const iter_difference_t n) { + { i += n } -> same_as; + { j + n } -> same_as; + { n + j } -> same_as; + { i -= n } -> same_as; + { j - n } -> same_as; + { j[n] } -> same_as>; + }; +``` + +### Parameters + +*`I`*\ +The type to test to see if it's a `random_access_iterator`. + +### Remarks + +A `random_access_iterator` has the capabilities of an `input_iterator`, `output_iterator`, `forward_iterator`, and `bidirectional_iterator`. + +Some examples of a `random_access_iterator` are `vector`, `array`, and `deque`. + +### Example: `random_access_iterator` + +The following example shows that a `vector` has a `random_access_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + // Show that vector has a random_access_iterator + std::cout << std::boolalpha << std::random_access_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::random_access_iterator; // outputs true +} +``` + +## `sentinel_for` + +Specifies that a type is a sentinel for an iterator. + +```cpp +template +concept sentinel_for = + semiregular && + input_or_output_iterator && + weakly-equality-comparable-with ; +``` + +### Parameters + +*`I`*\ +The iterator type. + +*`S`*\ +The type to test to see if it's a sentinel for `I`. + +### Remarks + +A sentinel is a type that can be compared to an iterator to determine if the iterator has reached the end. This concept determines if a type is a sentinel for one of the `input_or_output_iterator` types, which includes `input_iterator`, `output_iterator`, `forward_iterator`, `bidirectional_iterator`, `random_access_iterator`, and `contiguous_iterator`. + +### Example: `sentinel_for` + +The following example uses the `sentinel_for` concept to show that `vector::iterator` is a sentinel for `vector`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + std::vector v = {0, 1, 2}; + std::vector::iterator i = v.begin(); + // show that vector::iterator is a sentinel for vector + std::cout << std::boolalpha << std::sentinel_for::iterator, decltype(i)>; // outputs true +} +``` + +## `sized_sentinel_for` + +Test that an iterator and its sentinel can be subtracted using `-` to find the difference, in constant time. + +```cpp +template +concept sized_sentinel_for = + sentinel_for && + !disable_sized_sentinel_for, remove_cv_t> && + requires(const I& i, const S& s) { + {s - i} -> same_as>; + {i - s} -> same_as>; + }; +``` + +### Parameters + +*`I`*\ +The iterator type. + +*`S`*\ +The sentinel type to test. + +### Remarks + +### Example: `sized_sentinel_for` + +The following example uses the `sized_sentinel_for` concept to verify that the sentinel for a `vector` can be subtracted from the vectors iterator in constant time: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + std::vector v = { 1, 2, 3 }; + std::vector::iterator i = v.begin(); + std::vector::iterator end = v.end(); + // use the sized_sentinel_for concept to verify that i can be subtracted from end in constant time + std::cout << std::boolalpha << std::sized_sentinel_for << "\n"; // outputs true + std::cout << end - i; // outputs 3 +} +``` + +## See also + +[Range concepts](range-concepts.md)\ +[Range adaptors](range-adaptors.md)\ +[View classes](view-classes.md) \ No newline at end of file diff --git a/docs/standard-library/iterator-functions.md b/docs/standard-library/iterator-functions.md index e7ee68e1de9..17de7983ce5 100644 --- a/docs/standard-library/iterator-functions.md +++ b/docs/standard-library/iterator-functions.md @@ -1,13 +1,13 @@ --- description: "Learn more about: functions" title: " functions" -ms.date: 09/28/2022 +ms.date: "11/04/2016" f1_keywords: ["xutility/std::advance", "xutility/std::back_inserter", "xutility/std::begin", "xutility/std::cbegin", "xutility/std::cend", "xutility/std::distance", "xutility/std::end", "xutility/std::front_inserter", "xutility/std::inserter", "xutility/std::make_checked_array_iterator", "xutility/std::make_move_iterator", "xutility/std::make_unchecked_array_iterator", "xutility/std::next", "xutility/std::prev"] helpviewer_keywords: ["std::advance [C++]", "std::back_inserter [C++]", "std::begin [C++]", "std::cbegin [C++]", "std::cend [C++]", "std::distance [C++]", "std::end [C++]", "std::front_inserter [C++]", "std::inserter [C++]", "std::make_checked_array_iterator [C++]", "std::make_move_iterator [C++]", "std::make_unchecked_array_iterator [C++]", "std::next [C++]", "std::prev [C++]"] --- # `` functions -## ` advance` +## `advance` Increments an iterator by a specified number of positions. @@ -100,7 +100,7 @@ A `back_insert_iterator` associated with the container object *`Cont`*. ### Remarks -Within the C++ Standard Library, the argument must refer to one of the three sequence containers that have the member function `push_back`: [deque Class](../standard-library/deque-class.md), [list Class](../standard-library/list-class.md), or [vector Class](../standard-library/vector-class.md). +Within the C++ Standard Library, the argument must refer to one of the three sequence containers that have the member function `push_back`: [`deque` Class](../standard-library/deque-class.md), [`list` Class](../standard-library/list-class.md), or [`vector` Class](../standard-library/vector-class.md). ### Example @@ -236,7 +236,7 @@ int main() 160 106 80 70 53 40 35 23 20 16 10 8 5 4 2 1 ``` -The function `reverse_sort` supports containers of any kind, in addition to regular arrays, because it calls the non-member version of `begin()`. If `reverse_sort` were coded to use the container member `begin()`: +The function `reverse_sort` supports containers of any kind, in addition to regular arrays, because it calls the non-member version of `begin()`. Coding `reverse_sort` to use the container member `begin()`: ```cpp template @@ -249,7 +249,7 @@ void reverse_sort(C& c) { } ``` -Then sending an array to it would cause this compiler error: +Then sending an array to it, causes this compiler error: ```Output error C2228: left of '.begin' must have class/struct/union @@ -276,7 +276,7 @@ A constant `cont.begin()`. ### Remarks -This function works with all C++ Standard Library containers and with [initializer_list](../standard-library/initializer-list-class.md). +This function works with all C++ Standard Library containers and with [`initializer_list`](../standard-library/initializer-list-class.md). You can use this member function in place of the `begin()` template function to guarantee that the return value is `const_iterator`. Typically, it's used with the [`auto`](../cpp/auto-cpp.md) type deduction keyword, as shown in the following example. In the example, consider `Container` to be a modifiable (non- **`const`**) container or `initializer_list` of any kind that supports `begin()` and `cbegin()`. @@ -301,7 +301,7 @@ auto cend(const Container& cont) ### Parameters *`cont`*\ -A container or initializer_list. +A container or `initializer_list`. ### Return Value @@ -1031,7 +1031,7 @@ The template function returns `next` decremented `off` times. ## `rbegin` -Get an iterator which returns the elements of the container in reverse order. +Get an iterator, which returns the elements of the container in reverse order. ```cpp template constexpr auto rbegin(C& c) -> decltype(c.rbegin()); diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index b1e0fd13979..4c87768cbf0 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -1,15 +1,13 @@ --- -description: "Learn more about: " title: "" -ms.date: 09/29/2022 +description: "Learn more about: " +ms.date: 12/14/2022 f1_keywords: [""] helpviewer_keywords: ["iterator header"] --- # `` -Defines iterator primitives, predefined iterators and stream iterators, and several supporting templates. The predefined iterators include insert and reverse adaptors. - -There are three classes of insert iterator adaptors: front, back, and general. They provide insert semantics rather than overwrite semantics that the container member function iterators provide. +Defines predefined iterators and stream iterators, iterator primitives, and supporting templates. ## Requirements @@ -19,17 +17,9 @@ There are three classes of insert iterator adaptors: front, back, and general. T ## Remarks -Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range specified by a type of iterator. Any data structure that satisfies the requirements of the iterator can be operated upon by the algorithm. There are five types or categories of iterators: +Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range of values as specified by a kind of iterator. Algorithms can operate on any data structure that satisfies the requirements of the iterator. -| Kind | Direction | Read/Write| Example types| -|---|---|---|---| -| Output | Forward | Write | `ostream`, `inserter` | -| Input | Forward | Read | `istream`| -| Forward | Forward | Read/Write | | -| Bidirectional | Forward and backward | Read/Write | `list`, `set`, `multiset`, `map`, and `multimap`. | -| Random access | Any order | Read/Write | `vector`, `deque`, `string`, and `array`. | - -Iterators are arranged in a hierarchy of capability. In the table above, output iterators are at the low end of the hierarchy, and random-access iterators are at the high end. Iterators higher in the hierarchy can be used in place of those that are lower, but not vice-versa. For example, a random-access iterator can be used in place of a forward iterator, but not the other way around. +In C++20, there are six categories of iterators. Iterators are arranged in a hierarchy of capability. Their capabilities are specified by C++20 concepts. For a description of the various iterators and their capabilities, see [Iterator concepts](iterator-concepts.md) Visual Studio has added extensions to C++ Standard Library iterators to support debugging for checked and unchecked iterators. For more information, see [Safe Libraries: C++ Standard Library](../standard-library/safe-libraries-cpp-standard-library.md). @@ -97,6 +87,22 @@ Visual Studio has added extensions to C++ Standard Library iterators to support |[`reverse_iterator`](../standard-library/reverse-iterator-class.md)|The class template describes an object that behaves like a random-access iterator, only in reverse.| |[`unchecked_array_iterator`](../standard-library/unchecked-array-iterator-class.md)|A class that accesses an array using a random access, unchecked iterator. **Note:** This class is a Microsoft extension of the C++ Standard Library. Code implemented by using this function isn't portable to C++ Standard build environments that don't support this Microsoft extension.| +## Concepts + +The following concepts are defined in the `std` namespace. They apply to iterators, and are also related to the iterator categories for ranges described in [`` concepts](range-concepts.md). + +| Iterator concept | Description | +|--|--| +| [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator)C++20 | Specifies an iterator that can read and write both forwards and backwards. | +| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator)C++20 | Specifies an iterator whose elements are sequential in memory, the same size, and can be accessed using pointer arithmetic. | +| [`forward_iterator`](iterator-concepts.md#forward_iterator)C++20 | Specifies an iterator that can read (and possibly write) multiple times. | +| [`input_iterator`](iterator-concepts.md#input_iterator)C++20 | Specifies an iterator that you can read from at least once. | +| [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | +| [`output_iterator`](iterator-concepts.md#output_iterator) | Specifies an iterator that you can write to. | +| [`random_access_iterator`](iterator-concepts.md#random_access_iterator)C++20 | Specifies an iterator that you can read and write by index. | +| [`sentinel_for`](iterator-concepts.md#sentinel_for)C++20 | Specifies a sentinel for an iterator type. | +| [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | + ## See also [Header Files Reference](../standard-library/cpp-standard-library-header-files.md)\ diff --git a/docs/standard-library/join-view-class.md b/docs/standard-library/join-view-class.md index fbd23b5a24a..e9decfce05c 100644 --- a/docs/standard-library/join-view-class.md +++ b/docs/standard-library/join-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::join`](range-adaptors.md#join) | | **Underlying range** | Must satisfy [`input_range`](range-concepts.md#input_range) or higher | | **Element type** | Same as the underlying range | -| **View iterator category** | Supports `input_range` up to [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range being iterated | +| **View iterator category** | `input_range` up to [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range being iterated | | **Sized** | No | | **Is `const`-iterable** | Only if the underlying range is `const` iterable | | **Common range** | Only if the underlying range satisfies [`common_range`](range-concepts.md#common_range) | diff --git a/docs/standard-library/media/iterator-hiearchy.svg b/docs/standard-library/media/iterator-hiearchy.svg new file mode 100644 index 00000000000..b843e51f959 --- /dev/null +++ b/docs/standard-library/media/iterator-hiearchy.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + Page-1 + + + + Rectangle.1 + input_or_output_iterator + + + + + + + input_or_output_iterator + + Rectangle.3 + input_iterator + + + + + + + input_iterator + + Rectangle.4 + output_iterator + + + + + + + output_iterator + + Rectangle.5 + forward_iterator + + + + + + + forward_iterator + + Rectangle.6 + contiguous_iterator + + + + + + + contiguous_iterator + + Rectangle.7 + random_access_iterator + + + + + + + random_access_iterator + + Rectangle.8 + bidirectional_iterator + + + + + + + bidirectional_iterator + + Line Arrow.17 + + + + + + + + + + + Line Arrow.18 + + + + + + + + + + + Line Arrow.21 + + + + + + + + + + + Line Arrow.22 + + + + + + + + + + + Line Arrow.23 + + + + + + + + + + + Line Arrow.24 + + + + + + + + + + + Line Arrow.25 + + + + + + + + + + + diff --git a/docs/standard-library/media/ranges-iterator-hiearchy.svg b/docs/standard-library/media/ranges-iterator-hiearchy.svg new file mode 100644 index 00000000000..f16fab6d54c --- /dev/null +++ b/docs/standard-library/media/ranges-iterator-hiearchy.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + Page-1 + + + + Rectangle.3 + input_range + + + + + + + input_range + + Rectangle.4 + output_range + + + + + + + output_range + + Rectangle.5 + forward_range + + + + + + + forward_range + + Rectangle.6 + contiguous_range + + + + + + + contiguous_range + + Rectangle.7 + random_access_range + + + + + + + random_access_range + + Rectangle.8 + bidirectional_range + + + + + + + bidirectional_range + + Line Arrow.17 + + + + + + + + + + + Line Arrow.18 + + + + + + + + + + + Line Arrow.21 + + + + + + + + + + + Line Arrow.22 + + + + + + + + + + + Line Arrow.23 + + + + + + + + + + + diff --git a/docs/standard-library/media/src/iterator-hiearchy.vsdx b/docs/standard-library/media/src/iterator-hiearchy.vsdx new file mode 100644 index 00000000000..2b4b1e22373 Binary files /dev/null and b/docs/standard-library/media/src/iterator-hiearchy.vsdx differ diff --git a/docs/standard-library/media/src/range-iterator-hiearchy.vsdx b/docs/standard-library/media/src/range-iterator-hiearchy.vsdx new file mode 100644 index 00000000000..c37b38a7e5b Binary files /dev/null and b/docs/standard-library/media/src/range-iterator-hiearchy.vsdx differ diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 7e3d1f277ae..8b7218964a5 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -7,7 +7,7 @@ helpviewer_keywords: ["std::ranges [C++], all", "std::ranges [C++], all_t", "std --- # Range adaptors -Range adaptors create a *view* (one of the [View classes](view-classes.md) in the `std::views` namespace) from a range. We recommend that you use an adaptor in `std::ranges::views` instead of creating the view types directly. The adaptors are the intended way to access views. They're easier to use, and in some cases more efficient, than creating instances of the view types directly. +Range adaptors create a *view* (one of the [View classes](view-classes.md) in the `std::views` namespace) from a range. We recommend that you use an adaptor to create views instead of creating the view types directly. The adaptors are the intended way to access views. They're easier to use, and in some cases more efficient, than creating instances of the view types directly. A view is a lightweight object that refers to elements from a range. A view can: @@ -48,9 +48,9 @@ The first range adaptor, [`filter`](filter-view-class.md), provides a view that When a range adaptor produces a view, it doesn't incur the cost of transforming every element in the range to produce that view. The cost to process an element in the view is paid only when you access that element. -Creating a view only prepares to do work in the future. In the previous example, creating the view doesn't result in finding all the elements divisible by three. It also doesn't square the elements that it finds. That work happens only when you access an element in the view. +Creating a view is preparation to do work in the future. In the previous example, creating the view doesn't result in finding all the elements divisible by three or squaring those elements. Work happens only when you access an element in the view. -Elements of a view are usually the actual elements of the range that are used to create the view. The view usually doesn't own the elements ([`owning_view`](owning-view-class.md) is an exception); it just refers to them. Changing an element changes that element in the range that the view was created from. The following example shows this behavior: +Elements of a view are usually the actual elements of the range used to create the view. The view usually doesn't own the elements; it just refers to them, with the exception of [`owning_view`](owning-view-class.md). Changing an element changes that element in the range that the view was created from. The following example shows this behavior: ```cpp #include @@ -268,7 +268,7 @@ An iterator to the element in the range to start with. The element that the iter ### Return value -A [`span`](span-class.md) is returned if `it` is a `contiguous_iterator` for arrays, vectors, and other containers that store their elements contiguously. Otherwise, a [`subrange`](subrange-class.md) is returned. +A [`span`](span-class.md) is returned if `it` is a [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator) for arrays, vectors, and other containers that store their elements contiguously. Otherwise, a [`subrange`](subrange-class.md) is returned. ### Remarks diff --git a/docs/standard-library/range-concepts.md b/docs/standard-library/range-concepts.md index 5df829a4c64..edb1d88d974 100644 --- a/docs/standard-library/range-concepts.md +++ b/docs/standard-library/range-concepts.md @@ -1,13 +1,13 @@ --- -description: "Learn more about range concepts and range iterator concepts." -title: "Concepts for ranges and range iterators" -ms.date: 11/02/2022 +description: "Learn more about range concepts." +title: " concepts" +ms.date: 12/16/2022 f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_range", "ranges/std::ranges::borrowed_range", "ranges/std::ranges::common_range", "ranges/std::ranges::contiguous_range", "ranges/std::ranges::forward_range", "ranges/std::ranges::input_range", "ranges/std::ranges::output_range", "ranges/std::ranges::random_access_range", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_range", "ranges/std::ranges::view", "ranges/std::ranges::viewable_range"] helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_range", "std::ranges [C++], ranges::borrowed_range", "std::ranges [C++], ranges::common_range", "std::ranges [C++], ranges::contiguous_range", "std::ranges [C++], ranges::forward_range", "std::ranges [C++], ranges::input_range", "std::ranges [C++], ranges::output_range", "std::ranges [C++], ranges::random_access_range", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_range", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_range"] --- # `` concepts -Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, convey template argument requirements in a readable form, and provide more succinct template related compiler errors. +Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. Consider the following example, which defines a concept to prevent instantiating a template with a type that doesn't support division: @@ -48,29 +48,39 @@ int main() } ``` -When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 version 17.4p4 or later, the error that concept `dividable` evaluated to false will point directly to the expression requirement `(a / b)` that failed. +When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 version 17.4 preview 4, or later, the error that concept `dividable` evaluated to false will point directly to the expression requirement `(a / b)` that failed. -The following concepts are defined in `std::ranges` and are declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. +Range concepts are defined in the `std::ranges` namespace, and declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. + +There are six categories of ranges. They're related to the categories of iterators listed in [`` concepts](iterator-concepts.md). In order of increasing capability, the categories are: + +| Range concept | Description | +|--|--| +| [`output_range`](#output_range)
[`input_range`](#input_range) | Specifies a range that you can write to.
Specifies a range that you can read from once. | +| [`forward_range`](#forward_range) | Specifies a range that you can read (and possibly write) multiple times. | +| [`bidirectional_range`](#bidirectional_range) | Specifies a range that you can read and write both forwards and backwards. | +| [`random_access_range`](#random_access_range) | Specifies a range that you can read and write by index. | +| [`contiguous_range`](#contiguous_range) | Specifies a range whose elements are sequential in memory, are the same size, and can be accessed using pointer arithmetic. | + +In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. The exception is `input_range`, which can't be written to, so it doesn't have the capabilities of `output_range`. + +:::image type="content" source="media/ranges-iterator-hiearchy.svg" alt-text="Diagram of the ranges iterator hierarchy. input_range and output_range are the most basic iterators. forward_range is next and refines both input_range and output_range. bidirectional_range refines forward_range. random_access_range refines bidirectional_range. Finally, contiguous_range refines random_access_range"::: + +Other range concepts include: | Range concept | Description | |--|--| -| [`range`](#range)C++20 | A type that provides an iterator and a sentinel. | -| [`bidirectional_range`](#bidirectional_range)C++20 | Supports reading and writing forwards and backwards. | -| [`borrowed_range`](#borrowed_range)C++20 | The lifetime of the type's iterators aren't tied to the object's lifetime. | -| [`common_range`](#common_range)C++20 | The type of the iterator and the type of the sentinel are the same. | -| [`contiguous_range`](#contiguous_range)C++20 | The elements are sequential in memory and can be accessed by using pointer arithmetic. | -| [`forward_range`](#forward_range)C++20 | Supports reading (and possibly writing) a range multiple times. | -| [`input_range`](#input_range)C++20 | Supports reading at least once. | -| [`output_range`](#output_range)C++20 | Supports writing. | -| [`random_access_range`](#random_access_range)C++20 | Supports reading and writing by index. | +| [`range`](#range)C++20 | Specifies a type that provides an iterator and a sentinel. | +| [`borrowed_range`](#borrowed_range)C++20 | Specifies that the lifetime of the range's iterators aren't tied to the range's lifetime. | +| [`common_range`](#common_range)C++20 | Specifies that the type of the range's iterator and the type of the range's sentinel are the same. | | [`Simple_View`](#simple_view)C++20 | Not an official concept defined as part of the standard library, but used as a helper concept on some interfaces. | -| [`sized_range`](#sized_range)C++20 | Provides the number of elements in a range efficiently. | -| [`view`](#view)C++20 | Has efficient (constant time) move construction, assignment, and destruction. | -| [`viewable_range`](#viewable_range)C++20 | A type that either is a view or can be converted to one. | +| [`sized_range`](#sized_range)C++20 | Specifies a range that can provide its number of elements efficiently. | +| [`view`](#view)C++20 | Specifies a type that has efficient (constant time) move construction, assignment, and destruction. | +| [`viewable_range`](#viewable_range)C++20 | Specifies a type that either is a view or can be converted to one. | ## `bidirectional_range` -A `bidirectional_range` supports reading and writing forwards and backwards. +A `bidirectional_range` supports reading and writing the range forwards and backwards. ```cpp template @@ -85,7 +95,8 @@ The type to test to see if it's a `bidirectional_range`. ### Remarks -A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. +This kind of range supports [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) or greater. +A `bidirectional_iterator` has the capabilities of a [`forward_iterator`](iterator-concepts.md#forward_iterator), but can also iterate backwards. Some examples of a `bidirectional_range` are `std::set`, `std::vector`, and `std::list`. @@ -144,7 +155,7 @@ The type to test to see if it's a `contiguous_range`. ### Remarks -A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. +A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. This kind of range supports [`continguous_iterator`](iterator-concepts.md#contiguous_iterator), which is the most flexible of all the iterators. Some examples of a `contiguous_range` are `std::array`, `std::vector`, and `std::string`. @@ -178,7 +189,7 @@ true ## `forward_range` -A `forward_range` supports reading (and possibly writing) a `range` multiple times. +A `forward_range` supports reading (and possibly writing) the range multiple times. ```cpp template @@ -192,11 +203,11 @@ The type to test to see if it's a `forward_range`. ### Remarks -A `forward_iterator` can iterate over a range multiple times. +This kind of range supports [`forward_iterator`](iterator-concepts.md#forward_iterator) or greater. A `forward_iterator` can iterate over a range multiple times. ## `input_range` -An `input_range` is a `range` that can be read from at least once. +An `input_range` is a range that can be read from once. ```cpp template @@ -212,14 +223,14 @@ The type to test to see if it's an `input_range`. When a type meets the requirements of `input_range`: -- The `ranges::begin()` function returns an `input_iterator`. Calling `begin()` more than once on an `input_range` results in undefined behavior. +- The `ranges::begin()` function returns an [`input_iterator`](iterator-concepts.md#input_iterator). Calling `begin()` more than once on an `input_range` results in undefined behavior. - You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_range` isn't multi-pass. Incrementing an iterator invalidates any copies. - It can be used with `ranges::for_each`. -- It *at least* has an `input_iterator`. It may have a more capable iterator type. +- It supports `input_iterator` or greater. ## `output_range` -An `output_range` is a `range` that you can write to. +An `output_range` is a range that you can write to. ```cpp template @@ -232,15 +243,15 @@ concept output_range = range && output_iterator, T>; The type of the range. *`T`*\ -The type of the data to write to the `range`. +The type of the data to write to the range. ### Remarks -The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a `range` of type `R`. +The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. In other words, it supports [`output_iterator`](iterator-concepts.md#output_iterator) or greater. ## `random_access_range` -A `random_access_range` can read or write a `range` by index. +A `random_access_range` can read or write a range by index. ```cpp template @@ -255,7 +266,7 @@ The type to test to see if it's a `sized_range`. ### Remarks -A `random_access_range` is the most flexible iterator. It has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is also sortable. +This kind of range supports [`random_access_iterator`](iterator-concepts.md#random_access_iterator) or greater. A `random_access_range` has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is sortable. Some examples of a `random_access_range` are `std::vector`, `std::array`, and `std::deque`. @@ -327,7 +338,7 @@ The type to test to see if it's a `sized_range`. The requirements of a `sized_range` are that calling `ranges::size` on it: -- Doesn't modify the `range`. +- Doesn't modify the range. - Returns the number of elements in amortized constant time. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. Some examples of a `sized_range` are `std::list` and `std::vector`. @@ -366,7 +377,7 @@ The type to test to see if it's a view. ### Remarks -The essential requirement that makes a view composable is that it's cheap to move/copy. This is because the view is moved/copied when it's composed with another view. It must be a movable `range`. +The essential requirement that makes a view composable is that it's cheap to move/copy. This is because the view is moved/copied when it's composed with another view. It must be a movable range. `ranges::enable_view` is a trait used to claim conformance to the semantic requirements of the `view` concept. A type can opt in by: - publicly and unambiguously deriving from a specialization of `ranges::view_interface` diff --git a/docs/standard-library/range-functions.md b/docs/standard-library/range-functions.md index feb651b9b45..b242415843f 100644 --- a/docs/standard-library/range-functions.md +++ b/docs/standard-library/range-functions.md @@ -130,7 +130,7 @@ Get a `const` pointer to the first element in the contiguous range. ```cpp template -constexpr std::add_pointer_t> cdata(T&& rg); +constexpr std::add_pointer_t> cdata(T&& rg); ``` ### Parameters diff --git a/docs/standard-library/ranges.md b/docs/standard-library/ranges.md index 9e116824d39..ffc526bd0c1 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -1,14 +1,14 @@ --- title: "" description: "Get an overview of the Standard Template Library (STL) ranges." -ms.date: 11/02/2022 +ms.date: 12/06/2022 f1_keywords: [""] helpviewer_keywords: ["ranges"] --- # `` -At a high level, a *range* is something that you can iterate over. The containers, such as `vector` and `list`, in the C++ Standard Library are ranges. A range abstracts iterators in a way that simplifies and amplifies your ability to use the Standard Template Library (STL). +At a high level, a *range* is something that you can iterate over. A range is represented by an iterator that marks the beginning of the range and a sentinel that marks the end of the range. The sentinel may be the same type as the begin iterator, or it may be different. The containers, such as `vector` and `list`, in the C++ Standard Library are ranges. A range abstracts iterators in a way that simplifies and amplifies your ability to use the Standard Template Library (STL). STL algorithms usually take iterators that point to the portion of the collection that they should operate on. For example, consider how you sort a `vector` by using `std::sort()`. You pass two iterators that mark the beginning and end of the `vector`. That provides flexibility, but passing the iterators to the algorithm is extra work because you probably just want to sort the whole thing. @@ -31,10 +31,12 @@ std::transform(intermediate.begin(), intermediate.end(), std::back_inserter(outp With ranges, you can accomplish the same thing without needing the `intermediate` vector: ```cpp -// requires /std:c++latest -std::vector input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; +// requires /std:c++20 +std::vector input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; -auto output = input | std::views::filter([](const int n) {return n % 3 == 0; }) | std::views::transform([](const int n) {return n * n; }); +auto output = input + | std::views::filter([](const int n) {return n % 3 == 0; }) + | std::views::transform([](const int n) {return n * n; }); ``` Besides being easier to read, this code avoids the memory allocation that's required for the `intermediate` vector and its contents. It also allows you to compose two operations. @@ -43,9 +45,6 @@ In the preceding code, each element that's divisible by three is combined with a The result, `output`, is itself a kind of range called a *view*. -> [!NOTE] -> This example of ranges requires the [`/std:c++latest`](../build/reference/std-specify-language-standard-version.md) compiler option. Because post-release updates to `` in the C++20 standard are a work in progress, the features that require `std::views` aren't enabled yet under `/std:c++20`. - ## Views A view is a lightweight range. View operations--such as default construction, move construction/assignment, copy construction/assignment (if present), destruction, begin, and end--all happen in constant time regardless of the number of elements in the view. @@ -59,7 +58,7 @@ Views are composable, which is powerful. In the previous example, the view of ve The elements of a view are evaluated lazily. That is, the transformations that you apply to each element in a view aren't evaluated until you ask for the element. For example, if you run the following code in a debugger and put a breakpoint on the lines `auto divisible_by_three = ...` and `auto square = ...`, you'll see that you hit the `divisible_by_three` lambda breakpoint as each element in `input` is tested for divisibility by three. The `square` lambda breakpoint will be hit as the elements that are divisible by three are squared. ```cpp -// requires /std:c++latest +// requires /std:c++20 #include #include #include @@ -115,16 +114,17 @@ The range algorithms are almost identical to the corresponding iterator-pair alg | [`size`](range-functions.md#size)C++20 | Get the size of the range as an unsigned value. | | [`ssize`](range-functions.md#ssize)C++20 | Get the size of the range as a signed value. | -### Types of ranges +### Range concepts -How you view the elements of a range depends on its underlying iterator type. The iterator types are specified as C++20 concepts. +How you iterate over the elements of a range depends on its underlying iterator type. Ranges use C++ concepts that specify which iterator they support. In C++20, to say that concept *X* refines concept *Y* means that everything that satisfies concept *Y* also satisfies concept *X*. For example: *car*, *bus*, and *truck* all refine *vehicle*. -The range concepts mirror the hierarchy of iterator categories. The following table lists various range concepts, along with the types of containers that they can be applied to: +Some range concepts mirror the hierarchy of iterator categories. The following table lists various range concepts, along with the types of containers that they can be applied to. | Range concept | Description | Supported containers | |--|--|--| +| `std::ranges::output_range` | Can iterate forward. | | `std::ranges::input_range` | Can iterate from beginning to end at least once. | `std::forward_list`
`std::unordered_map`
`std::unordered_multimap`
`std::unordered_set`
`std::unordered_multiset`
`basic_istream_view` | | `std::ranges::forward_range` | Can iterate from beginning to end more than once. | `std::forward_list`
`std::unordered_map`
`std::unordered_multimap`
`std::unordered_set`
`std::unordered_multiset` | | `std::ranges::bidirectional_range` | Can iterate forward and backward more than once. | `std::list`
`std::map`
`std::multimap`
`std::multiset`
`std::set`| diff --git a/docs/standard-library/single-view-class.md b/docs/standard-library/single-view-class.md index ba71f2e2b08..775d0531a49 100644 --- a/docs/standard-library/single-view-class.md +++ b/docs/standard-library/single-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::single`](range-adaptors.md#single) | | **Underlying range** | None | | **Element type** | Specified when the `single_view` is created | -| **View iterator category** | Supports `contiguous_range` | +| **View iterator category** | `contiguous_range` | | **Sized** | Always returns 1 | | **Is `const`-iterable** | Yes | | **Common range** | Yes | diff --git a/docs/standard-library/span-class.md b/docs/standard-library/span-class.md index 8661c026d95..be60468ddbf 100644 --- a/docs/standard-library/span-class.md +++ b/docs/standard-library/span-class.md @@ -912,7 +912,7 @@ A `span` doesn't free storage for items in the `span` because it doesn't own the |---------|---------| |`span()` | Construct an empty `span`. Only considered during overload resolution when the template parameter `Extent` is `0` or `dynamic_extent`.| |`span(It first, size_type count)` | Construct a `span` from the first `count` elements from iterator `first`. Only considered during overload resolution when template parameter `Extent` isn't `dynamic_extent`. | -|`span(It first, End last)` | Construct a `span` from the elements in iterator `first` until the end `last` is reached. Only considered during overload resolution when template parameter `Extent` isn't `dynamic_extent`. `It` must be a `contiguous_iterator`. | +|`span(It first, End last)` | Construct a `span` from the elements in iterator `first` until the end `last` is reached. Only considered during overload resolution when template parameter `Extent` isn't `dynamic_extent`. `It` must be a [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator). | |`span(array& arr) noexcept;`

`span(const array& arr) noexcept;`

`span(type_identity_t (&arr)[N]) noexcept;` | Construct a `span` from `N` elements of the specified array. Only considered during overload resolution when template parameter `Extent` is `dynamic_extent` or equals `N`. | |`span(R&& r)` | Construct a `span` from a range. Only participates in overload resolution if template parameter `Extent` isn't `dynamic_extent`.| |`span(const span& other)` | The compiler-generated copy constructor. A shallow copy of the data pointer is safe because the `span` doesn't allocate the memory to hold the elements. | diff --git a/docs/standard-library/subrange-class.md b/docs/standard-library/subrange-class.md index 8eac6cfa217..b0fe6497e74 100644 --- a/docs/standard-library/subrange-class.md +++ b/docs/standard-library/subrange-class.md @@ -21,13 +21,13 @@ class subrange : public view_interface> ### Template parameters *`I`*\ - The begin iterator type. The `input_or_output_iterator` concept ensures that *`I`* is an iterator that can read all of the elements. + The begin iterator type. The [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator) concept ensures that *`I`* is an iterator that can read all of the elements. *`K`*\ The kind of subrange: Use `subrange_kind::sized` to specify a sized subrange. Use `sized_sentinel_for` if the iterator and sentinel can be subtracted to yield the size. The requirement `subrange_kind::sized || !sized_sentinel_for` stores the size locally in the subrange object, and requires that you construct the subrange either using the constructor that takes a [`sized_range`](range-concepts.md#sized_range) (for which you would specify `subrange_kind::sized` here) or via the constructor that takes an `iterator`, `sentinel`, and `size` (so you would specify `sized_sentinel_for` here). *`S`*\ - The end iterator type. The `sized_sentinel_for` concept ensures that *`S`* can be used as a sentinel for *`I`* and that it's possible to compute the distance between the sentinel and the current iterator position in *`I`* in constant time. + The end iterator type. The [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for) concept ensures that *`S`* can be used as a sentinel for *`I`* and that it's possible to compute the distance between the sentinel and the current iterator position in *`I`* in constant time. ## View characteristics @@ -105,7 +105,7 @@ Iterator that points to the first element in the subrange. Sentinel that points to the end of the subrange. The element it points to isn't included in the subrange. *`sizeHint`*\ -The size of the range in elements. This is used to optimize the `size` member function and is necessary if you want to make a sized `subrange` from an iterator and sentinel whose types don't model `sized_sentinel_for`. +The size of the range in elements. This is used to optimize the `size` member function and is necessary if you want to make a sized `subrange` from an iterator and sentinel whose types don't model [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for). For information about template parameter types, see [Template parameters](#template-parameters). diff --git a/docs/standard-library/toc.yml b/docs/standard-library/toc.yml index 53e4ea22ad9..30544a93602 100644 --- a/docs/standard-library/toc.yml +++ b/docs/standard-library/toc.yml @@ -592,6 +592,8 @@ items: items: - name: href: iterator.md + - name: concepts + href: iterator-concepts.md - name: functions href: iterator-functions.md - name: operators diff --git a/docs/standard-library/transform-view-class.md b/docs/standard-library/transform-view-class.md index 21c1eeabaa6..e80c25dc5be 100644 --- a/docs/standard-library/transform-view-class.md +++ b/docs/standard-library/transform-view-class.md @@ -1,7 +1,7 @@ --- title: "transform_view class (C++ Standard Library)| Microsoft Docs" description: "API reference for the Standard Template Library (STL) transform_view class, which is a view of an underlying sequence after applying a transformation function to each element." -ms.date: 10/07/2022 +ms.date: 12/14/2022 f1_keywords: ["ranges/std::transform_view", "ranges/std::transform_view::base", "ranges/std::transform_view::begin", "ranges/std::transform_view::empty", "ranges/std::transform_view::end", "ranges/std::transform_view::operator bool", "ranges/std::transform_view::back", "ranges/std::transform_view::front", "ranges/std::transform_view::operator[]"] helpviewer_keywords: ["std::ranges::transform_view [C++]", "std::ranges::transform_view::base [C++]", "std::ranges::transform_view::begin [C++]", "std::ranges::transform_view::empty [C++]", "std::ranges::transform_view::end [C++]", "std::ranges::transform_view::back [C++]", "std::ranges::transform_view::front [C++]", "std::ranges::transform_view::operator bool [C++]", "std::ranges::transform_view::operator[] [C++]"] dev_langs: ["C++"] @@ -37,7 +37,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::transform`](range-adaptors.md#transform) | | **Underlying range** | Must satisfy [`input_range`](range-concepts.md#input_range) or higher | | **Element type** | Same as the transformation function's return type. | -| **View iterator category** | Supports [`input_range`](range-concepts.md#input_range) up to `random_access`, depending on the underlying range | +| **View iterator category** | Supports [`input_range`](range-concepts.md#input_range) up to [`random_access_range`](range-concepts.md#random_access_range), depending on the underlying range | | **Sized** | Only if the underlying range satisfies [`sized_range`](range-concepts.md#sized_range) | | **Is `const`-iterable** | Only if the underlying range is `const` iterable and the transformation works on `const` references. | | **Common range** | Only if the underlying range satisfies [`common_range`](range-concepts.md#common_range) | diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index e5fe0ff24d4..bf9815b2dd2 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -1,19 +1,19 @@ --- -description: "Learn more about view classes, which allow you to inexpensively refer to and transform ranges." +description: "Learn more about the ranges view classes, which allow you to inexpensively transform ranges." title: "View classes" -ms.date: 11/04/2022 +ms.date: 12/20/2022 f1_keywords: ["RANGES/std::ranges::views", "RANGES/std::views"] helpviewer_keywords: ["RANGES/VIEWS/std", "VIEWS/std"] --- -# View classes +# `` view classes -A *view* is a lightweight range that refers to elements that it doesn't own (except for [`owning_view`](owning-view-class.md)). A view is typically based on another range and provides a different way of looking at it, whether by transforming or filtering it. For example, [`std::views::filter`](filter-view-class.md) is a view that uses the criteria that you specify to select elements from another range. +A *view* is a lightweight range that refers to elements that it doesn't own (except [`owning_view`](owning-view-class.md)). A view is typically based on another range and provides a different way of looking at it, whether by transforming or filtering it. For example, [`std::views::filter`](filter-view-class.md) is a view that uses the criteria that you specify to select elements from another range. -When you access the elements in a view, it's done "lazily" so that work is done only when you get an element. This also makes it possible to combine, or *compose*, views without a performance penalty. +When you access the elements in a view, it's done "lazily" so that work is done only when you get an element. This makes it possible to combine, or *compose*, views without a performance penalty. For example, you could create a view that provides only the even elements from a range and then transform them by squaring them. The work to do the filtering and transformation is done only for the elements that you access, and only when you access them. -A view can be copied, assigned, and destroyed in constant time no matter how many elements it contains. This is because a view doesn't own the elements that it refers to, so it doesn't need to make a copy. This is also why you can compose views without a performance penalty. +A view can be copied, assigned, and destroyed in constant time no matter how many elements it contains. This is because a view doesn't own the elements that it refers to, so it doesn't need to make a copy. This is why you can compose views without a performance penalty. You typically create a view by using a [range adaptor](range-adaptors.md). Range adaptors are the intended way to create a view, are easier to use than instantiating the view classes directly, and are sometimes more efficient than instantiating the view classes directly. The view classes are exposed directly in case you need to create your own custom view type based on an existing view type. @@ -31,8 +31,9 @@ int main() auto divisible_by_three = [](const int n) {return n % 3 == 0;}; auto square = [](const int n) {return n * n;}; - auto x = input | std::views::filter(divisible_by_three) - | std::views::transform(square); + auto x = input + | std::views::filter(divisible_by_three) + | std::views::transform(square); for (int i : x) { @@ -47,7 +48,7 @@ int main() Using a view after the range that it's based on is modified can lead to undefined behavior. For example, a [`reverse_view`](reverse-view-class.md) based on a vector shouldn't be reused if you add or remove elements from the underlying vector. Modifying the underlying vector invalidates the container's `end` iterator--including the copy of the iterator that the view might have made. -Because views are cheap to create, you should generally re-create a view if you modify the underlying range. The following example demonstrates this. It also shows how to store a view pipeline in a variable so that you can reuse it. +Because views are cheap to create, you should generally re-create a view if you modify the underlying range. The following example demonstrates how to store a view pipeline in a variable so that you can reuse it. ```cpp // requires / std:c++20 or later @@ -122,15 +123,15 @@ The following view classes are defined in the `std::ranges` namespace. | [`transform_view`](transform-view-class.md)C++20 | A view of an underlying sequence after a transformation function is applied to each element. | | [`values_view`](values-view-class.md)C++20 | A view over the second index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of the `int` elements from each tuple. | -Many of these classes have corresponding [range adaptors](range-adaptors.md) in the `std:views` namespace that creates them. Prefer the adaptors in `std::views` to creating view classes directly. The range adaptors are the intended access points, are easier to use, and in some cases are more efficient. +Many of these classes have corresponding [range adaptors](range-adaptors.md) in the `std:views` namespace that creates instances of them. Prefer using an adaptor to create a view instead of creating view classes directly. The range adaptors are the intended way to create views, are easier to use, and in some cases are more efficient. ## View classes characteristics Each view class topic has a **Characteristics** section after the syntax section. The **Characteristics** section has the following entries: * **Range adaptor**: A link to the range adaptor that creates the view. You typically use a range adaptor to create a view rather than create a view class directly, so it's listed here for convenience. -* **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See the following table for the hierarchy of iterators. -* **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a `bidirectional_iterator` category, even if the underlying range has a `random_access_iterator` category. +* **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See [ranges iterator hierarchy](#ranges-iterator-hierarchy) for more information about the kinds of iterators. +* **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator), even if the underlying range has a [`random_access_iterator`](iterator-concepts.md#random_access_iterator). * **Element type**: The type of the elements that the view's iterator returns. * **Sized**: Whether the view can return the number of elements that it refers to. Not all views can. * **Common range**: Specifies whether the view is a [`common_range`](range-concepts.md#common_range), which means that the begin iterator and sentinel types are the same. Common ranges are useful for pre-range code that works with iterator pairs. An example is iterator pair constructors for a sequence container, like `vector(ranges::begin(x), ranges::end(x))`. @@ -143,24 +144,24 @@ Each view class topic has a **Characteristics** section after the syntax section Range algorithms that return iterators (or subranges) do so only when their arguments are lvalues (non-temporaries) or borrowed ranges. Otherwise, they return a `std::dangling` object, which provides a hint in error messages about what went wrong if you tried to use it like an iterator. * **Is `const` iterable**: Indicates whether you can iterate over a `const` instance of the view. Not all `const` views can be iterated. If a view isn't `const` iterable, you can't iterate with `for (const auto& element : as_const(theView))` or pass it to a function that takes a `const` reference to the view and then tries to iterate over it. -### Iterator hierarchy +### Ranges iterator hierarchy -The iterator category that **Range adaptor** and **View iterator category** mention in the **Characteristics** section refers to the hierarchy of iterators that ranges and views support. +In the **Characteristics** section of each view class topic, the iterator category in **Underlying range** and **View iterator category** refers to the kind of iterator that the range/view supports. There are six categories of Ranges iterators, which are identified by C++20 concepts. The hierarchy of range iterators, in increasing order of capability, is: -That hierarchy, in increasing order of capability, is: - -| Range iterator category | Description | +| Range iterator concept | Description | |--|--| | [`output_range`](range-concepts.md#output_range) | Write-only, only moves forward; single-pass. | -| [`input_range`](range-concepts.md#input_range) | Only moves forward; single-pass. | -| `forward_range` | Only moves forward; multi-pass. | +| [`input_range`](range-concepts.md#input_range) | Read-only, only moves forward; single-pass. | +| [`forward_range`](range-concepts.md#forward_range) | Only moves forward; multi-pass. | | [`bidirectional_range`](range-concepts.md#bidirectional_range) | Can move forward and backward; multi-pass. | -| `random_access_range` | Can access the collection with an index; multi-pass. | -| `contiguous_range` | Can access the collection with an index, and elements are stored contiguously in memory. | +| [`random_access_range`](range-concepts.md#random_access_range) | Can access the collection with an index; multi-pass. | +| [`contiguous_range`](range-concepts.md#contiguous_range) | Can access the collection with an index, and elements are stored contiguously in memory. | + +Generally speaking, an iterator has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) has the capabilities of [`forward_range`](range-concepts.md#forward_range), but not vice versa. Except `input_range`, which doesn't have the capability of `output_range` because you can't write to an `input_range`. -An iterator also has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) can be used with a [`forward_range`](range-concepts.md#forward_range) iterator, but not vice versa. +The statement "requires `input_range` or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator, because they're all as capable as `input_range`. -The statement "requires [`input_range`](range-concepts.md#input_range) or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, [`random_access_range`](range-concepts.md#random_access_range), or `contiguous_range` iterator, because any of those categories is as capable as `input_range`. +The ranges iterator hierarchy is directly related to the iterator hierarchy. For more information, see [Iterator concepts](iterator-concepts.md). ## See also diff --git a/docs/standard-library/view-interface.md b/docs/standard-library/view-interface.md index 1799109b400..c165ead51ec 100644 --- a/docs/standard-library/view-interface.md +++ b/docs/standard-library/view-interface.md @@ -94,7 +94,7 @@ A pointer to the first element in the derived view. ### Remarks -The iterator for the derived view must satisfy `contiguous_iterator`. +The iterator for the derived view must satisfy [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator). ## `empty` @@ -164,7 +164,7 @@ The number of elements in the derived view. ### Remarks -The iterator for the derived view must satisfy `sized_sentinel_for`. +The iterator for the derived view must satisfy [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for). ## `operator[]`