From 0ebe7cb20aa9cac5f10ac78970b9c06a9bdea23b Mon Sep 17 00:00:00 2001 From: Nicolas Morales Date: Tue, 27 Feb 2024 15:37:11 -0700 Subject: [PATCH] minor fixes for mdarray. These include using reference types in is_assignable_v, fixing broken references, fixing incorrectly rendered pnum, and adding template arguments to mdspan conversion operator --- P0009/wg21/data/index.yaml | 9 +- P1684-mdarray/P1684.html | 100 +++++----- P1684-mdarray/P1684.md | 366 ++++++++++++++++++------------------- 3 files changed, 244 insertions(+), 231 deletions(-) diff --git a/P0009/wg21/data/index.yaml b/P0009/wg21/data/index.yaml index f321068a..636d3d2e 100644 --- a/P0009/wg21/data/index.yaml +++ b/P0009/wg21/data/index.yaml @@ -83180,7 +83180,14 @@ references: - family: H. Carter Edwards, Bryce Adelstein Lelbach, Daniel Sunderland, David Hollman, Christian Trott, Mauro Bianco, Ben Sander, Athanasios Iliopoulos, John Michopoulos, Mark Hoemmen issued: year: 2019 - URL: https://wg21.link/p0009r9 + - id: P0009R18 + citation-label: P0009R18 + title: "mdspan" + author: + - family: Christian Trott, D.S. Hollman, Damien Lebrun-Grandie, Mark Hoemmen, Daniel Sunderland, H. Carter Edwards, Bryce Adelstein Lelbach, Mauro Bianco, Ben Sander, Athanasios Iliopoulos, John Michopoulos, Nevin Liber + issued: + year: 2022 + URL: https://wg21.link/p0009r18 - id: P0010R0 citation-label: P0010R0 title: "Adding a subsection for concurrent random number generation in C++17" diff --git a/P1684-mdarray/P1684.html b/P1684-mdarray/P1684.html index 6225b431..ae7b4070 100644 --- a/P1684-mdarray/P1684.html +++ b/P1684-mdarray/P1684.html @@ -4,7 +4,7 @@ - + mdarray: An Owning Multidimensional Array Analog of mdspan - + @@ -425,7 +425,7 @@

mdarray: An Date: - 2023-05-19 + 2024-02-27 Project: @@ -593,18 +593,17 @@

2 Motivation

-

[P0009R18?] proposed -mdspan, a nonowning multidimensional array abstraction. It -was voted into the C++23 draft. This proposal builds on -mdspan by introducing mdarray, an -owning multidimensional array that interoperates with -mdspan. The mdarray class is to -vector as mdspan is to span. -Owning semantics can make it easier for users to express common cases, -like returning an array from a function. It also makes it much easier to -create a multi dimensional array for use:

+

[P0009R18] proposed mdspan, +a nonowning multidimensional array abstraction. It was voted into the +C++23 draft. This proposal builds on mdspan by introducing +mdarray, an owning multidimensional array that +interoperates with mdspan. The mdarray class +is to vector as mdspan is to +span. Owning semantics can make it easier for users to +express common cases, like returning an array from a function. It also +makes it much easier to create a multi dimensional array for use:

C++23:

-
// Create a mapping so one knows how many 
+
// Create a mapping so one knows how many
 // elements the buffer needs to have
 layout_right::mapping<dextents<int, 2>> map(N,M);
 
@@ -626,9 +625,9 @@ 

3 Des the design of mdspan as much as possible, with the goals of reducing cognitive load for users already familiar with mdspan and of incorporating the lessons learned from over a -decade of experience with [P0009R18?] and -libraries of similar design. This paper assumes the reader has read and -is already familiar with [P0009R18?].

+decade of experience with [P0009R18] and libraries of similar +design. This paper assumes the reader has read and is already familiar +with [P0009R18].

3.1 Design overview

The analogy to mdspan can be seen in the declaration of the proposed design for mdarray.

@@ -638,8 +637,8 @@

3 class Container = see-below> class mdarray;

This intentionally parallels the design of mdspan in -[P0009R18?], which has -the following signature.

+[P0009R18], which has the following +signature.

template<class ElementType,
          class Extents,
          class LayoutPolicy = layout_right,
@@ -735,7 +734,7 @@ 

template<class ElementType, class Extents, class LayoutPolicy, class Container>
 class mdarray {
   /* ... */
-  
+
   // only in mdarray:
   using mdspan_type = /* ... */;
   using const_mdspan_type = /* ... */;
@@ -744,10 +743,10 @@ 

operator mdspan() const; template<class OtherAccessorType = default_accessor<element_type>> - auto to_mdspan(const OtherAccessorType& a = + auto to_mdspan(const OtherAccessorType& a = default_accessor<element_type>()) const noexcept; template<class OtherAccessorType = default_accessor<const element_type>> - auto to_mdspan(const OtherAccessorType& a = + auto to_mdspan(const OtherAccessorType& a = default_accessor<const element_type>()) const noexcept; /* ... */ @@ -761,7 +760,7 @@

template<class ElementType, class Extents, class LayoutPolicy, class Container>
 class mdarray {
   /* ... */
-  
+
   // only in mdarray
  using container_type = Container;
 
@@ -779,7 +778,7 @@ 

template<class ElementType, class Extents, class LayoutPolicy, class ContainerPolicy>
 class mdarray {
   /* ... */
-  
+
   // analogous to mdspan:
   template<class ET, class Exts, class LP, class CP>
     constexpr mdarray(const mdarray<ET, Exts, LP, CP>&);
@@ -871,10 +870,10 @@ 

As with mdspan, the Extents template parameter to mdarray shall be a template instantiation of -std::extents, as described in [P0009R18?]. The -concerns addressed by this aspect of the design are exactly the same in -mdarray and mdspan, so using the same form and -mechanism seems like the right thing to do here.

+std::extents, as described in [P0009R18]. The concerns addressed by +this aspect of the design are exactly the same in mdarray +and mdspan, so using the same form and mechanism seems like +the right thing to do here.

3.4 LayoutPolicy design reused

While not quite as straightforward, the decision to use the same @@ -919,7 +918,7 @@

array of the correct size:

auto a = mdarray<int, 3, 3>();
-std::array<int, 9> data = get-underlying-container(a); 
+std::array<int, 9> data = get-underlying-container(a);

(Whether or not a reference to the underlying container should be obtainable is slightly less clear, though we see no reason why this should not be allowed.) The default for an mdarray with @@ -930,7 +929,7 @@

vector, so an entirely reasonable outcome would be to have:

auto a = mdarray<int, 3, dynamic_extent>();
-std::vector<int> data = get-underlying-container(a); 
+std::vector<int> data = get-underlying-container(a);

Moreover, taking a view of a mdarray should yield an analogous mdspan with consistent semantics (except, of course, that the latter is nonowning). We provisionally call the method @@ -1765,7 +1764,7 @@

6 Wo mdarray is a multidimensional array of elements.

namespace std {
 
-template<class ElementType, class Extents, class LayoutPolicy, class Container = 
+template<class ElementType, class Extents, class LayoutPolicy, class Container =
          vector<ElementType>>
 class mdarray {
 public:
@@ -1811,7 +1810,7 @@ 

6 Wo constexpr mdarray(const mapping_type& m, container_type&& c,); - template<class OtherElementType, class OtherExtents, + template<class OtherElementType, class OtherExtents, class OtherLayoutPolicy, class OtherContainer> explicit(see below) constexpr mdarray( @@ -1846,12 +1845,12 @@

6 Wo constexpr mdarray(const mapping_type& m, container_type&& c, const Alloc& a); - template<class OtherElementType, class OtherExtents, - class OtherLayoutPolicy, class OtherContainer, + template<class OtherElementType, class OtherExtents, + class OtherLayoutPolicy, class OtherContainer, class Alloc> explicit(see below) constexpr mdarray( - const mdarray<OtherElementType, OtherExtents, + const mdarray<OtherElementType, OtherExtents, OtherLayoutPolicy, OtherContainer>& other, const Alloc& a); template<class OtherElementType, class OtherExtents, @@ -1891,8 +1890,8 @@

6 Wo constexpr const mapping_type& mapping() const { return map_; } template<class OtherElementType, class OtherExtents, - class OtherLayoutType, class OtherAccessorType> - constexpr operator mdspan () const; + class OtherLayoutPolicy, class OtherAccessorType> + constexpr operator mdspan<OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorType> () const; template<class OtherAccessorType = default_accessor<element_type>> constexpr mdspan<element_type, extents_type, layout_type, OtherAccessorType> @@ -2291,7 +2290,7 @@

6 Wo
template<class OtherElementType, class OtherExtents,
          class OtherLayoutPolicy, class OtherContainer>
   explicit(see below)
-  constexpr mdarray(const mdarray<OtherElementType, OtherExtents, 
+  constexpr mdarray(const mdarray<OtherElementType, OtherExtents,
                                 OtherLayoutPolicy, OtherContainer>& other);

24 Mandates:

@@ -2639,7 +2638,7 @@

6 Wo
template<class OtherElementType, class OtherExtents,
          class OtherLayoutPolicy, class OtherContainer, class Alloc>
   explicit(see below)
-  constexpr mdarray(const mdarray<OtherElementType, OtherExtents, 
+  constexpr mdarray(const mdarray<OtherElementType, OtherExtents,
                                   OtherLayoutPolicy, OtherContainer>& other,
                     const Alloc& a);

25 @@ -2834,16 +2833,17 @@

6 Wo
swap(x.ctr_, y.ctr_);
 swap(x.map_, y.map_);
  template<class OtherElementType, class OtherExtents,
-           class OtherLayoutType, class OtherAccessorType>
+           class OtherLayoutPolicy, class OtherAccessorType>
   operator mdspan ();

11 Constraints:

    -
  • [11.1]{pnum} -is_assignable_v<mdspan<element_type, extents_type, layout_type>, mdspan<OtherElementType, OtherExtents, OtherLayoutType, OtherAccessorType>> -is true.

  • -
  • [11.2]{pnum} is_same_v<pointer, element_type*> +

  • (11.1) +is_assignable_v<mdspan_type &, mdspan<OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorType>> is true.

  • +
  • (11.2) +is_same_v<pointer, element_type*> is +true.

12 Preconditions: @@ -2857,7 +2857,7 @@

6 Wo to_mdspan(const OtherAccessorType& a = default_accessor<element_type>());

14 Constraints: -is_assignable_v<pointer, typename OtherAccessorType::data_handle_type> +is_assignable_v<pointer &, typename OtherAccessorType::data_handle_type> is true.

15 Preconditions: @@ -2871,7 +2871,7 @@

6 Wo to_mdspan(const OtherAccessorType& a = default_accessor<const element_type>()) const;

17 Constraints: -is_assignable_v<const_pointer, typename OtherAccessorType::data_handle_type> +is_assignable_v<const_pointer &, typename OtherAccessorType::data_handle_type> is true.

18 Preconditions: @@ -2899,6 +2899,12 @@

7< Office of Science and the National Nuclear Security Administration.

8 References

+
+
[P0009R18]
Christian Trott, D.S. Hollman, Damien +Lebrun-Grandie, Mark Hoemmen, Daniel Sunderland, H. Carter Edwards, +Bryce Adelstein Lelbach, Mauro Bianco, Ben Sander, Athanasios +Iliopoulos, John Michopoulos, Nevin Liber. 2022. mdspan.
https://wg21.link/p0009r18
+
[P1684R0]
David Hollman, Christian Trott, Mark Hoemmen, Daniel Sundernland. 2019. mdarray: An Owning Multidimensional Array diff --git a/P1684-mdarray/P1684.md b/P1684-mdarray/P1684.md index 030e32b0..ba55b415 100644 --- a/P1684-mdarray/P1684.md +++ b/P1684-mdarray/P1684.md @@ -27,17 +27,17 @@ author: - disambiguate deduction guides - add precondition to relevant functions about container size being large enough: this fixes issues in moved-from state - add function `extract_container` to move the container out of `mdarray` -- rename `data()` to `container_data()` and add `container_size()` +- rename `data()` to `container_data()` and add `container_size()` - `data()` did actually not go together with `size()` for example for non-unique layouts - in moved from state `data()` also may not work together with `mapping().required_span_size()`. - work around the fact that `data()` and `pointer` is not a thing required by contiguous container requirements ... -- fix `to_mdspan` and `mdspan` conversion operator +- fix `to_mdspan` and `mdspan` conversion operator ## P1684R4: 2023-01 Mailing #### Changes from R3 -- drop the "size constructible container" requirements and simply use preconditions on relevant constructors +- drop the "size constructible container" requirements and simply use preconditions on relevant constructors ## P1684R3: 2022-07 Mailing @@ -77,12 +77,12 @@ author: # Motivation -[@P0009R18] proposed `mdspan`, a nonowning multidimensional array abstraction. It was voted into the C++23 draft. This proposal builds on `mdspan` by introducing `mdarray`, an *owning* multidimensional array that interoperates with `mdspan`. The `mdarray` class is to `vector` as `mdspan` is to `span`. Owning semantics can make it easier for users to express common cases, like returning an array from a function. +[@P0009R18] proposed `mdspan`, a nonowning multidimensional array abstraction. It was voted into the C++23 draft. This proposal builds on `mdspan` by introducing `mdarray`, an *owning* multidimensional array that interoperates with `mdspan`. The `mdarray` class is to `vector` as `mdspan` is to `span`. Owning semantics can make it easier for users to express common cases, like returning an array from a function. It also makes it much easier to create a multi dimensional array for use: **C++23:** ```cpp -// Create a mapping so one knows how many +// Create a mapping so one knows how many // elements the buffer needs to have layout_right::mapping> map(N,M); @@ -216,7 +216,7 @@ We would be happy to change this based on design direction from LEWG. template class mdarray { /* ... */ - + // only in mdarray: using mdspan_type = /* ... */; using const_mdspan_type = /* ... */; @@ -225,10 +225,10 @@ class mdarray { operator mdspan() const; template> - auto to_mdspan(const OtherAccessorType& a = + auto to_mdspan(const OtherAccessorType& a = default_accessor()) const noexcept; template> - auto to_mdspan(const OtherAccessorType& a = + auto to_mdspan(const OtherAccessorType& a = default_accessor()) const noexcept; /* ... */ @@ -245,7 +245,7 @@ while `mdarray` has a `Container` template parameter. template class mdarray { /* ... */ - + // only in mdarray using container_type = Container; @@ -264,7 +264,7 @@ Since `mdarray` has owning semantics, we also need move-like versions of these: template class mdarray { /* ... */ - + // analogous to mdspan: template constexpr mdarray(const mdarray&); @@ -334,7 +334,7 @@ class mdarray { Moreover, containers such as `vector` and container adapters like `queue` have a significant number of other constructors which copy the data on input, such as constructors taking ranges, input iterator pairs, and initializer lists. The R2 version of this paper had a number of those, but in combination with allocator arguments it lead to an explosion of constructors. -A draft version seen by LEWG on 2022-07-12 sported 41 constructors. +A draft version seen by LEWG on 2022-07-12 sported 41 constructors. However almost all these constructors would simply forward arguments to the constructor of the container owned by `mdarray`. LEWG provided feedback that we should consider reducing the amount of constructors, since at a minimum one could inline construct the `container` itself, and move it into the `mdarray` upon construction. @@ -346,7 +346,7 @@ mdarray a(first, last, N, M); mdarray a(std::move(vector(first, last)), N, M); ``` -In R3 we decided to radically cut back on constructors and simply leave those out. +In R3 we decided to radically cut back on constructors and simply leave those out. Finally, `mdarray` does not have the analog of `mdspan`'s constructor that takes an `array` of dynamic extents. This avoids any ambiguity or confusion with a constructor that takes a container instance, in the case where the `container` happens to be an `array`. @@ -376,7 +376,7 @@ Regardless of the form of the solution, there are several use cases where we hav ```cpp auto a = mdarray(); -std::array data = @*get-underlying-container*@(a); +std::array data = @*get-underlying-container*@(a); ``` (Whether or not a reference to the underlying container should be obtainable is slightly less clear, though we see no reason why this should not be allowed.) The default for an `mdarray` with variable extents is only slightly less clear, though it should almost certainly meet the requirements of *contiguous container* (**[container.requirements.general]**/13). @@ -384,7 +384,7 @@ The default model for *contiguous container* of variable size in the standard li ```cpp auto a = mdarray(); -std::vector data = @*get-underlying-container*@(a); +std::vector data = @*get-underlying-container*@(a); ``` Moreover, taking a view of a `mdarray` should yield an analogous `mdspan` with consistent semantics (except, of course, that the latter is nonowning). We provisionally call the method for taking a view of an `mdarray` "`to_mdspan()`": @@ -398,7 +398,7 @@ void frobnicate(mdarray data) } ``` -In order for this to work, `Container::data()` should be required to return `T*`. +In order for this to work, `Container::data()` should be required to return `T*`. That way, interoperability with `mdspan` is trivial, since it can simply be created as: ```cpp @@ -417,14 +417,14 @@ since they imbue additional semantics to what is otherwise an ordinary container These all take a `Container` template parameter, which defaults to `deque` for `stack` and `queue`, and to `vector` for `priority_queue`. The allocation concern is thus delegated to the container concept, reducing the cognitive load associated with the design. While this design approach overconstrains the template parameter slightly -(that is, not all of the requirements of the `Container` concept are needed by the container adaptors), +(that is, not all of the requirements of the `Container` concept are needed by the container adaptors), the simplicity arising from concept reuse more than justifies the cost of the extra constraints. It is difficult to say whether the use of `Container` directly, as with the container adaptors, is also the correct approach for `mdarray`. There are pieces of information that may need to be customized in some very reasonable use cases that are not provided by the standard container concept. The most important of these is the ability to produce a semantically consistent `AccessorPolicy` when creating a `mdspan` that refers to a `mdarray`. (Interoperability between `mdspan` and `mdarray` is considered a critical design requirement because of the nearly complete overlap in the set of algorithms that operate on them.) -For instance, given a `Container` instance `c` and an `AccessorPolicy` instance `a`, the behavior of `a.access(p, n)` should be consistent with the behavior of `c[n]` +For instance, given a `Container` instance `c` and an `AccessorPolicy` instance `a`, the behavior of `a.access(p, n)` should be consistent with the behavior of `c[n]` for a `mdspan` wrapping `a` that is a view of a `mdarray` wrapping `c` (if `p` is `c.begin()`). But because `c[n]` is part of the container requirements and thus may encapsulate any arbitrary mapping from an offset of `c.begin()` to a reference, the only reasonable means of preserving these semantics for arbitrary container types is to reference the original container directly in the corresponding `AccessorPolicy`. @@ -590,7 +590,7 @@ public: The above sketch makes clear the biggest challenge with this approach: the mismatch in shallow versus deep `const`ness in for an abstractions designed to support `mdspan` and `mdarray`, respectively. The `ContainerPolicy` concept thus requires additional `const`-qualified overloads of the basis operations. -Moreover, while the `ContainerPolicy` itself can be obtained directly from the corresponding `AccessorPolicy` +Moreover, while the `ContainerPolicy` itself can be obtained directly from the corresponding `AccessorPolicy` in the case of the non-`const` method for creating the corresponding `mdspan` (provisionally called `view()`), the `const`-qualified version needs to adapt the policy, since the nested types have the wrong names (e.g., `const_pointer` should be named `pointer` from the perspective of the `mdspan` that the `const`-qualified `view()` needs to return). @@ -617,7 +617,7 @@ private: Compared to simply using a `container` as the argument, this approach has the benefit of enabling `mdarray` to use containers for which `data()[i]` is not giving access to the same element as `container[i]`. However, after more consideration we believe that the need for supporting such containers as underlying storage for `mdarray` is likely fairly niche. -Furthermore, we believe one could later extent the design of `mdarray` to allow for such ContainerPolicies, even if the initial design only allows for a restricted set of containers. +Furthermore, we believe one could later extent the design of `mdarray` to allow for such ContainerPolicies, even if the initial design only allows for a restricted set of containers. ### Extension for accessor policy from container @@ -633,7 +633,7 @@ We have to somehow guarantee that containers constructed from sizes (or if such are actually large enough after the construction so we can index into them. However, we don't want full sequence container requirements (also there is no named requirement for a constructor which takes an integral only). -To illustrate the problem consider a user defined container with a static size but that has a constructor which takes an init value. +To illustrate the problem consider a user defined container with a static size but that has a constructor which takes an init value. ```c++ user::static_vector vec(1000); @@ -641,7 +641,7 @@ user::static_vector vec(1000); assert(vec.size()==200); ``` -From the perspective of `mdarray` this container looks like its constructible from a size, but that is not actually what the container does. +From the perspective of `mdarray` this container looks like its constructible from a size, but that is not actually what the container does. We previously proposed a new set of named optional requirements for containers which guarantee the desired behavior. @@ -673,7 +673,7 @@ We put the emphasis on easy usability in most common cases, while preserving cla There are two alternatives we considered based on received feedback: - A minimal approach just providing the extents/mapping overloads and versions of it which take a container - - A variadic approach with perfect forwarding of arguments to the internal container constructor. + - A variadic approach with perfect forwarding of arguments to the internal container constructor. All variants have the converting constructors, and also the constructors from mdspan in addition to the combinations listed here. @@ -718,7 +718,7 @@ However, it would make some common use cases very verbose to write when using va some_mdarray_t a(extents{...}, vector(layout_right::mapping{extents{...}}.required_span_size(), value)); ``` -instead of +instead of ```c++ some_mdarray_t a(extents{...}, value); @@ -786,149 +786,149 @@ In this table we use these shorthands: - `mda`: an `mdarray` object, not necessarily the same type as `mda_t` - `mds`: an `mdspan` obejct, not necessarily the same as returned by `mda_t::to_mdspan` - - - - - - - - - - - - - - - +
ArgumentsCurrentMinimalVariadic
`default` `mda_t()` `mda_t()` `mda_t()`
+ + + + + + - - - - - + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + + - - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + - -
ArgumentsCurrentMinimalVariadic
integrals `mda_t(10, 10)` `mda_t(10, 10)` `mda_t(10, 10)`
`default` `mda_t()` `mda_t()` `mda_t()`
mapping/extents `mda_t(me)` `mda_t(me)` `mda_t(me)`
integrals `mda_t(10, 10)` `mda_t(10, 10)` `mda_t(10, 10)`
container + integrals `mda_t(extents{10, 10}, c)` `mda_t(extents{10, 10}, c)` `mda_t(extents{10, 10}, c)`
mapping/extents `mda_t(me)` `mda_t(me)` `mda_t(me)`
move container + integrals `mda_t(extents{10, 10}, move(c))` `mda_t(extents{10, 10}, move(c))` `mda_t(extents{10, 10}, move(c))`
container + integrals `mda_t(extents{10, 10}, c)` `mda_t(extents{10, 10}, c)` `mda_t(extents{10, 10}, c)`
container + mapping/extents `mda_t(me, c)` `mda_t(me, c)` `mda_t(me, c)`
move container + integrals `mda_t(extents{10, 10}, move(c))` `mda_t(extents{10, 10}, move(c))` `mda_t(extents{10, 10}, move(c))`
move container + mapping `mda_t(me, move(c))` `mda_t(me, move(c))` `mda_t(me, move(c))`
container + mapping/extents `mda_t(me, c)` `mda_t(me, c)` `mda_t(me, c)`
container + alloc + mapping/extents `mda_t(me, c, a)` `mda_t(me, c_t(c,a))` `mda_t(me, c, a)`
move container + mapping `mda_t(me, move(c))` `mda_t(me, move(c))` `mda_t(me, move(c))`
move container + alloc + mapping `mda_t(me, move(c), a)` `mda_t(me, c_t(move(c),a))` `mda_t(me, move(c), a)` container + alloc + mapping/extents `mda_t(me, c, a)` `mda_t(me, c_t(c,a))` `mda_t(me, c, a)`
extents + value `mda_t(e, v)` `mda_t(e, c_t(map_t(e).required_span_size(), v))` `mda_t(e, v)` move container + alloc + mapping `mda_t(me, move(c), a)` `mda_t(me, c_t(move(c),a))` `mda_t(me, move(c), a)`
mapping + value `mda_t(m, v)` `mda_t(m, c_t(m.required_span_size(), v))` `mda_t(m, v)`
extents + value `mda_t(e, v)` `mda_t(e, c_t(map_t(e).required_span_size(), v))` `mda_t(e, v)`
mapping + custom container size `mda_t(m, c_t(s))` `mda_t(m, c_t(s))` `mda_t(m, c_t(s))` or `mda_t(m, s)` for integrals not convertible to `value_type`
mapping + value `mda_t(m, v)` `mda_t(m, c_t(m.required_span_size(), v))` `mda_t(m, v)`
mapping + custom container size + value `mda_t(m, c_t(s, v))` `mda_t(m, c_t(s, v))` `mda_t(m, s, v)`
mapping + custom container size `mda_t(m, c_t(s))` `mda_t(m, c_t(s))` `mda_t(m, c_t(s))` or `mda_t(m, s)` for integrals not convertible to `value_type`
extents + value + alloc `mda_t(e, v, a)` `mda_t(e, c_t(map_t(e).required_span_size(), v, a)))` `mda_t(e, v , a)` mapping + custom container size + value `mda_t(m, c_t(s, v))` `mda_t(m, c_t(s, v))` `mda_t(m, s, v)`
mapping + value + alloc `mda_t(m, v, a)` `mda_t(m, move(c_t(m.required_span_size(), v, a)))` `mda_t(m, v, a)`
extents + value + alloc `mda_t(e, v, a)` `mda_t(e, c_t(map_t(e).required_span_size(), v, a)))` `mda_t(e, v , a)`
mapping + custom container size + alloc `mda_t(m, c_t(s, a))` `mda_t(m, c_t(s, a))` `mda_t(m, c_t(s, a))` or `mda_t(m, s, a)` for integrals not convertible to `value_type`
mapping + value + alloc `mda_t(m, v, a)` `mda_t(m, move(c_t(m.required_span_size(), v, a)))` `mda_t(m, v, a)`
mapping + custom container size + alloc `mda_t(m, c_t(s, a))` `mda_t(m, c_t(s, a))` `mda_t(m, c_t(s, a))` or `mda_t(m, s, a)` for integrals not convertible to `value_type`
mapping + custom container size + value + alloc `mda_t(m, c_t(s, v, a))` `mda_t(m, c_t(s, v, a))` `mda_t(m, s, v, a)`
mapping + custom container size + value + alloc `mda_t(m, c_t(s, v, a))` `mda_t(m, c_t(s, v, a))` `mda_t(m, s, v, a)`
iterators `mda_t(m, c_t(begin, end))` `mda_t(m, c_t(begin, end))` `mda_t(m, begin, end)`
iterators `mda_t(m, c_t(begin, end))` `mda_t(m, c_t(begin, end))` `mda_t(m, begin, end)`
range `mda_t(m, c_t(r))` `mda_t(m, c_t(r))` `mda_t(m, r)`
range `mda_t(m, c_t(r))` `mda_t(m, c_t(r))` `mda_t(m, r)`
converting mdarray `mda_t(mda)` `mda_t(mda)` `mda_t(mda)`
converting mdarray `mda_t(mda)` `mda_t(mda)` `mda_t(mda)`
compatible mdspan `mda_t(mds)` `mda_t(mds)` `mda_t(mds)`
compatible mdspan `mda_t(mds)` `mda_t(mds)` `mda_t(mds)`
compatible mdspan + allocator `mda_t(mds, a)` `mda_t(mds, a)` `mda_t(mds, a)` compatible mdspan + allocator `mda_t(mds, a)` `mda_t(mds, a)` `mda_t(mds, a)`
+ + # Move Behavior @@ -966,7 +966,7 @@ Insert the following after section 24.6.6 ```c++ namespace std { -template> class mdarray { public: @@ -1012,7 +1012,7 @@ public: constexpr mdarray(const mapping_type& m, container_type&& c,); - template explicit(@_see below_@) constexpr mdarray( @@ -1047,12 +1047,12 @@ public: constexpr mdarray(const mapping_type& m, container_type&& c, const Alloc& a); - template explicit(@_see below_@) constexpr mdarray( - const mdarray& other, const Alloc& a); template - constexpr operator mdspan () const; + class OtherLayoutPolicy, class OtherAccessorType> + constexpr operator mdspan () const; template> constexpr mdspan @@ -1190,7 +1190,7 @@ mdarray(const mdspan&, const Alloc&) * [5.1]{.pnum} `is_nothrow_move_constructible_v` is `true` if `is_nothrow_move_constructible_v` is `true`, * [5.2]{.pnum} `is_nothrow_move_assignable_v` is `true` if `is_nothrow_move_assignable_v` is `true` , and - + * [5.3]{.pnum} `is_nothrow_swappable_v` is `true` if `is_nothrow_swappable_v` is `true`. [6]{.pnum} A specialization of `mdarray` is a trivially copyable type if its `container_type` and `mapping_type` are @@ -1246,7 +1246,7 @@ template [2]{.pnum} *Preconditions:* * [2.1] Let `map` be `mapping_type(extents_type(static_cast(std::move(exts)...)))`, then - + * [2.2]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise * [2.3]{.pnum} `map.required_span_size() <= size(container_type(map.required_span_size()))` is `true`. @@ -1267,10 +1267,10 @@ constexpr mdarray(const extents_type& ext); * [4.2]{.pnum} if `container_type` is not a specialization of `array`, `is_constructible_v` is `true`. -[5]{.pnum} *Preconditions:* +[5]{.pnum} *Preconditions:* * [5.1]{.pnum} Let `map` be `mapping_type(ext)`, then - + * [5.2]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise * [5.3]{.pnum} `map.required_span_size() <= size(container_type(map.required_span_size()))` is `true`. @@ -1288,7 +1288,7 @@ constexpr mdarray(const mapping_type& map); [7]{.pnum} *Constraints:* if `container_type` is not a specialization of `array`, `is_constructible_v` is `true`. -[8]{.pnum} *Preconditions:* +[8]{.pnum} *Preconditions:* * [8.1]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise @@ -1311,10 +1311,10 @@ constexpr mdarray(const extents_type& ext, const value_type& val); * [10.2]{.pnum} if `container_type` is not a specialization of `array`, `is_constructible_v` is `true`. -[11]{.pnum} *Preconditions:* +[11]{.pnum} *Preconditions:* * [11.1]{.pnum} Let `map` be `mapping_type(ext)`, then - + * [11.2]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise * [11.3]{.pnum} `map.required_span_size() <= size(container_type(map.required_span_size()))` is `true`. @@ -1324,7 +1324,7 @@ constexpr mdarray(const extents_type& ext, const value_type& val); * [12.1]{.pnum} Direct-non-list-initializes _`map_`_ with `ext`, and * [12.2]{.pnum} if `is_constructible_v` is `true`, - direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise + direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise direct-non-list-initializes `ctr_` with _`value-to-array`_`())>()`. @@ -1334,7 +1334,7 @@ constexpr mdarray(const mapping_type& m, const value_type& val); [13]{.pnum} *Constraints:* if `container_type` is not a specialization of `array`, `is_constructible_v` is `true`. -[14]{.pnum} *Preconditions:* +[14]{.pnum} *Preconditions:* * [14.1]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise @@ -1345,7 +1345,7 @@ constexpr mdarray(const mapping_type& m, const value_type& val); * [15.1]{.pnum} Direct-non-list-initializes _`map_`_ with `m`, and * [15.2]{.pnum} if `is_constructible_v` is `true`, - direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise + direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise direct-non-list-initializes `ctr_` with _`value-to-array`_`())>()`. ```c++ @@ -1407,17 +1407,17 @@ constexpr mdarray(const mapping_type& m, container_type&& c); template explicit(@_see below_@) - constexpr mdarray(const mdarray& other); ``` -[24]{.pnum} *Mandates:* +[24]{.pnum} *Mandates:* * [24.1]{.pnum} `is_constructible_v` is `true`, and * [24.2]{.pnum} `is_constructible_v` is `true`. -[25]{.pnum} *Constraints:* +[25]{.pnum} *Constraints:* * [25.1]{.pnum} `is_constructible_v&>` is `true`, and @@ -1455,9 +1455,9 @@ template` is `true`, * [30.3]{.pnum} `is_default_constructible_v` is `true`, - + * [30.4]{.pnum} `is_constructible_v&>` is `true`, and - + * [30.5]{.pnum} if `container_type` is not a specialization of `array`, `is_constructible_v` is `true`. [31]{.pnum} *Preconditions:* @@ -1496,10 +1496,10 @@ template * [1.2]{.pnum} `is_constructible_v` is `true`. -[2]{.pnum} *Preconditions:* +[2]{.pnum} *Preconditions:* * [2.1]{.pnum} Let `map` be `mapping_type(ext)`, then - + * [2.2]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise * [2.3]{.pnum} `map.required_span_size() <= size(container_type(map.required_span_size(), a))` is `true`. @@ -1518,7 +1518,7 @@ template [4]{.pnum} *Constraints:* `is_constructible_v` is `true`. -[5]{.pnum} *Preconditions:* +[5]{.pnum} *Preconditions:* * [5.1]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise @@ -1541,10 +1541,10 @@ constexpr mdarray(const extents_type& ext, const value_type& val, const Alloc& a * [7.2]{.pnum} if `container_type` is not a specialization of `array`, `is_constructible_v` is `true`. -[8]{.pnum} *Preconditions:* +[8]{.pnum} *Preconditions:* * [8.1]{.pnum} Let `map` be `mapping_type(ext)`, then - + * [8.2]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise * [8.3]{.pnum} `map.required_span_size() <= size(container_type(map.required_span_size(), val, a))` is `true`. @@ -1554,7 +1554,7 @@ constexpr mdarray(const extents_type& ext, const value_type& val, const Alloc& a * [9.1]{.pnum} Direct-non-list-initializes _`map_`_ with `ext`, and * [9.2]{.pnum} if `is_constructible_v` is `true`, - direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise + direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise direct-non-list-initializes `ctr_` with _`value-to-array`_`())>()`. @@ -1565,7 +1565,7 @@ constexpr mdarray(const mapping_type& map, const value_type& val, const Alloc& a [10]{.pnum} *Constraints:* if `container_type` is not a specialization of `array`, `is_constructible_v` is `true`. -[11]{.pnum} *Preconditions:* +[11]{.pnum} *Preconditions:* * [11.1]{.pnum} if `container_type` is a specialization of `array`, `map.required_span_size() <= size(container_type())` is `true`, otherwise @@ -1576,7 +1576,7 @@ constexpr mdarray(const mapping_type& map, const value_type& val, const Alloc& a * [12.1]{.pnum} Direct-non-list-initializes _`map_`_ with `map`, and * [12.2]{.pnum} if `is_constructible_v` is `true`, - direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise + direct-non-list-initializes `ctr_` with `container_type(`_`map_`_`.required_span_size(), val)`, otherwise direct-non-list-initializes `ctr_` with _`value-to-array`_`())>()`. @@ -1656,12 +1656,12 @@ template template explicit(@_see below_@) - constexpr mdarray(const mdarray& other, const Alloc& a); ``` -[25]{.pnum} *Mandates:* +[25]{.pnum} *Mandates:* * [25.1]{.pnum} `is_constructible_v` is `true`, and @@ -1710,7 +1710,7 @@ template` is `true`, * [31.4]{.pnum} `is_default_constructible_v` is `true`, and - + * [31.5]{.pnum} `is_constructible_v&>` is `true`. @@ -1767,10 +1767,10 @@ template [2]{.pnum} Let `I` be `extents_type::`_`index-cast`_`(std::move(indices))`. -[3]{.pnum} *Preconditions:* - +[3]{.pnum} *Preconditions:* + * [3.1]{.pnum} `I` is a multidimensional index in `extents()`. - [Note: This implies that _`map_`_`(I...) < `_`map_`_`.required_span_size()` is `true`.— end note]; + [Note: This implies that _`map_`_`(I...) < `_`map_`_`.required_span_size()` is `true`.— end note]; * [3.2]{.pnum} `container_size() >= `_`map_`_`.required_span_size()` is `true`. [4]{.pnum} *Effects:* Equivalent to: `return ` _`acc_`_`.access(`_`ptr_`_`, `_`map_`_`(static_cast(std::move(indices))...));` @@ -1790,7 +1790,7 @@ template [5]{.pnum} *Constraints:* * [5.1]{.pnum} `is_convertible_v` is `true`, and - + * [5.2]{.pnum} `is_nothrow_constructible_v` is `true`. [6]{.pnum} *Effects:* Let `P` be a parameter pack such that @@ -1822,15 +1822,15 @@ swap(x.@_map_@_, y.@_map_@_); ```c++ template + class OtherLayoutPolicy, class OtherAccessorType> operator mdspan (); ``` [11]{.pnum} *Constraints:* - * [11.1]{pnum} `is_assignable_v, mdspan>` is `true`. + * [11.1]{.pnum} `is_assignable_v>` is `true`. - * [11.2]{pnum} `is_same_v` is `true`. + * [11.2]{.pnum} `is_same_v` is `true`. [12]{.pnum} *Preconditions:* `container_size() >= `_`map_`_`.required_span_size()` is `true`. @@ -1842,7 +1842,7 @@ swap(x.@_map_@_, y.@_map_@_); to_mdspan(const OtherAccessorType& a = default_accessor()); ``` -[14]{.pnum} *Constraints:* `is_assignable_v` is `true`. +[14]{.pnum} *Constraints:* `is_assignable_v` is `true`. [15]{.pnum} *Preconditions:* `container_size() >= `_`map_`_`.required_span_size()` is `true`. @@ -1854,7 +1854,7 @@ swap(x.@_map_@_, y.@_map_@_); to_mdspan(const OtherAccessorType& a = default_accessor()) const; ``` -[17]{.pnum} *Constraints:* `is_assignable_v` is `true`. +[17]{.pnum} *Constraints:* `is_assignable_v` is `true`. [18]{.pnum} *Preconditions:* `container_size() >= `_`map_`_`.required_span_size()` is `true`.