<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Better <code>mdspan</code>'s CTAD</title>
  <style type="text/css">
    body {
      font-variant-ligatures: none;
    }

    p {
      text-align: justify
    }

    li {
      text-align: justify
    }

    blockquote.note,
    div.note {
      background-color: #E0E0E0;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }

    p code {
      color: navy
    }

    ins p code {
      color: #00A000
    }

    p ins code {
      color: #00A000
    }

    p del code {
      color: #A00000
    }

    ins {
      color: #00A000
    }

    del {
      color: #A00000
    }

    table#boilerplate {
      border: 0
    }

    table#boilerplate td {
      padding-left: 2em
    }

    table.bordered,
    table.bordered th,
    table.bordered td {
      border: 1px solid;
      text-align: center;
    }

    ins.block {
      color: #00A000;
      text-decoration: none
    }

    del.block {
      color: #A00000;
      text-decoration: none
    }

    #hidedel:checked~* del,
    #hidedel:checked~* del * {
      display: none;
      visibility: hidden
    }
  </style>
</head>

<body data-new-gr-c-s-check-loaded="14.1043.0" data-gr-ext-installed="">
  <table id="boilerplate">
    <tbody>
      <tr>
        <td>Document number</td>
        <td>P3029R1</td>
      </tr>
      <tr>
        <td>Date</td>
        <td>2024-03-20</td>
      </tr>
      <tr>
        <td>Audience</td>
        <td>LEWG</td>
      </tr>
      <tr>
        <td>Reply-to</td>
        <td>Hewill Kang &lt;hewillk@gmail.com&gt;</td>
      </tr>
    </tbody>
  </table>
  <hr>
  <h1>Better <code>mdspan</code>'s CTAD</h1>
  <ul>
    <li>
      <ul>
        <li>Abstract</li>
        <li>Revision history</li>
        <li>Discussion</li>
        <li>Design</li>
        <li>Proposed change</li>
        <li>References</li>
      </ul>
    </li>
  </ul>
  <a name="Abstract"></a>
  <h2>Abstract</h2>
  <p>This paper makes <code>span</code> and <code>mdspan</code>' CTAD <code>integral_constant</code>-aware to deduce
    more efficient types.</p>

  <a name="Revision history"></a>
  <h2>Revision history</h2>
  <p>
  <h3>R0</h3>
  <p>Initial revision.</p>
  </p>
  <p>
  <h3>R1</h3>
  <p>
  <ol>
    <li>
      Changed the comma in CTAD of <code>span(It, EndOrSize)</code>, which is part of the wording, to green.
    </li>
    <li>
      Initialized the <code><i>maybe-static-ext</i></code>'s specialization with <code>{T::value}</code> to prevent
      conversions from negative values.
    </li>
    <li>
      Aligned with the latest working draft.
    </li>
  </ol>
  </p>
  <a name="Discussion"></a>
  <h2>Discussion</h2>
  <p>
    Currently, <code>mdspan</code>'s most common pointer-indices CTAD have the following definitions:
  </p>
  <pre>
  template&lt;class ElementType, class... Integrals&gt;
    requires((is_convertible_v&lt;Integrals, size_t&gt; && ...) && sizeof...(Integrals) > 0)
    explicit mdspan(ElementType*, Integrals...)
      -> mdspan&lt;ElementType, dextents&lt;size_t, sizeof...(Integrals)&gt;&gt;;
</pre>
  <p>
    Since the <code>Extents</code> template parameter of <code>mdspan</code> is explicitly specified as
    <code>dextents</code>, the deduced type always has dynamic extent,
    even if we pass a compile-time constant:
  </p>
  <pre>
  mdspan ms (p, 3, 4, 5); // <span style="color:red;font-weight:bolder">mdspan&lt;int, extents&lt;size_t, dynamic_extent, dynamic_extent, dynamic_extent&gt;&gt;</span>
  mdspan ms2(p, 3, integral_constant&lt;size_t, 4&gt;{}, 5);                              // <span style="color:red;font-weight:bolder">ditto</span>
  mdspan ms3(p, integral_constant&lt;size_t, 3&gt;{}, 4, integral_constant&lt;size_t, 5&gt;{}); // <span style="color:red;font-weight:bolder">ditto</span>
</pre>
  <p>
    This result feels wrong to me. If <code>integral_constant</code> represents a compile-time constant, why don't we
    take advantage of it and make it reflect the extent of <code>mdspan</code>, since we already did this with
    <code>strided_slice</code>?
  </p>
  <p>The author believes that instead of setting static extents by additionally creating <code>extents</code>:
  </p>
  <pre>
  mdspan ms2(p, extents&lt;size_t, dynamic_extent, 4, dynamic_extent&gt;(3, 5)); // <span style="color:red;font-weight:bolder">mdspan&lt;int, extents&lt;size_t, dynamic_extent, 4, dynamic_extent&gt;&gt;</span>
  mdspan ms3(p, extents&lt;size_t, 3, dynamic_extent, 5&gt;(4));                 // <span style="color:red;font-weight:bolder">mdspan&lt;int, extents&lt;size_t, 3, dynamic_extent, 5&gt;&gt;</span>
</pre>
  <p>
    It would be better to automatically make the first example equivalent based on whether the argument is a
    compile-time constant.</p>
  <p>This brings the following benefits:</p>
  </p>
  <ol>
    <li>
      It enables defining dynamic or static extents with the similar form and intuitively reflects the extent type.
    </li>
    <li>
      It's less error-prone as we don't need to calculate how many <code>dynamic_extents</code>
      there are to pass in the correct number of arguments. The compiler already handle it for us.
    </li>
    <li>
      It makes defining <code>mdspan</code> more concise, an <code>mdspan</code> with mixed extents now can be spelled
      as
      <code>mdspan(c_&lt;3&gt;{}, 4, c_&lt;5&gt;{})</code> (benefit from <a
        href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2781r3.html">P2781</a>
      <code>std::constexpr_v</code>).
    </li>
  </ol>

  <a name="Design"></a>
  <h2>Design</h2>
  <p>
  <h3><code>span</code>'s CTAD</h3>
  <p>
    The paper also applies to <code>span</code>' CTAD for consistency.
    In other words, <code>span(p, c_&lt;5&gt;{})</code> will be deduced as <code>span&lt;int, 5&gt;</code>.
    The author doesn't think this is a big issue as it's relative intuitive and generally users don't often write this
    way.
  </p>
  <p>
  <h3><code>mdspan</code>'s CTAD</h3>
  <p>Given that <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2630r4.html">P2630</a>
    <code>std::submdspan</code> already introduced <code><i>integral-constant-like</i></code> for checking
    <code>integral_constant</code>-like type,
    this paper reuses it to detect whether <code>mdspan</code>'s arguments are a compile-time constant. This also
    applies to <code>extents</code>.
  </p>
  </p>
  <a name="Proposed-change"></a>
  <h2>Proposed change</h2>
  <p>This wording is relative to <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4971.pdf">N4971</a>.
  </p>
  </div>
  <div>
    <ol>
      <ol>
        <li>
          <p>Edit 24.7.2.1 <a href="https://eel.is/c++draft/span.syn">[span.syn]</a> as indicated:</p>
          <pre>
namespace std {
  // <i>constants</i>
  inline constexpr size_t dynamic_extent = numeric_limits&lt;size_t&gt;::max();

<ins>  template&lt;class T&gt;
    concept <i>integral-constant-like</i> =        // <i>exposition only</i>
      is_integral_v&lt;decltype(T::value)&gt; &&
      !is_same_v&lt;bool, remove_const_t&lt;decltype(T::value)&gt;&gt; &&
      convertible_to&lt;T, decltype(T::value)&gt; &&
      equality_comparable_with&lt;T, decltype(T::value)&gt; &&
      bool_constant&lt;T() == T::value&gt;::value &&
      bool_constant&lt;static_cast&lt;decltype(T::value)&gt;(T()) == T::value&gt;::value;</ins>

  <ins>template&lt;class T&gt;
    constexpr size_t <i>maybe-static-ext</i> = dynamic_extent;        // <i>exposition only</i>
  template&lt;<i>integral-constant-like</i> T&gt;
    constexpr size_t <i>maybe-static-ext</i>&lt;T&gt; = {T::value};</ins>

  // <i><a href="https://eel.is/c++draft/views.span">[views.span]</a>, class template span</i>
  template&lt;class ElementType, size_t Extent = dynamic_extent&gt;
    class span;
  [&hellip;]
}
  </pre>
        </li>
        <li>
          <p>Edit 24.7.2.2.1 <a href="https://eel.is/c++draft/span.overview">[span.overview]</a> as indicated:</p>
          <p>-2- All member functions of span have constant time complexity.</p>
          <pre>
namespace std {
  template&lt;class ElementType, size_t Extent = dynamic_extent&gt;
  class span {
    [&hellip;]
  };

  template&lt;class It, class EndOrSize&gt;
    span(It, EndOrSize) -> span&lt;remove_reference_t&lt;iter_reference_t&lt;It&gt&gt<ins>, <i>maybe-static-ext</i>&lt;EndOrSize&gt;</ins>&gt;;
  [&hellip;]
}
</pre>
        </li>
        <li>
          <p>Edit 24.7.2.2.3 <a href="https://eel.is/c++draft/span.deduct">[span.deduct]</a> as indicated:</p>
          <pre>
template&lt;class It, class EndOrSize&gt;
  span(It, EndOrSize) -> span&lt;remove_reference_t&lt;iter_reference_t&lt;It&gt&gt<ins>, <i>maybe-static-ext</i>&lt;EndOrSize&gt;</ins>&gt;;
</pre>
          <p>-1- <i>Constraints</i>: <code>It</code> satisfies <code>contiguous_iterator</code>.</p>
        </li>
        <li>
          <p>Edit 24.7.3.3.3 <a href="https://eel.is/c++draft/mdspan.extents.cons">[mdspan.extents.cons]</a> as
            indicated:</p>
          <pre>
template&lt;class... Integrals&gt;
  explicit extents(Integrals...) -> <i>see below</i>;
</pre>
          <p>-1- <i>Constraints</i>: <code>(is_convertible_v&lt;Integrals, size_t&gt; && ...)</code> is
            <code>true</code>.
          </p>
          <p>-2- <i>Remarks</i>: The deduced type is
            <code><del>d</del>extents&lt;size_t, <ins><i>maybe-static-ext</i>&lt;Integrals&gt;...</ins><del>sizeof...(Integrals)</del>&gt;</code>.
          </p>
        </li>
        <li>
          <p>Edit 24.7.3.2 <a href="https://eel.is/c++draft/mdspan.syn">[mdspan.syn]</a> as indicated:</p>
          <pre>
namespace std {
  [&hellip;]
  <del>template&lt;class T&gt;
    concept <i>integral-constant-like</i> =        // <i>exposition only</i>
      is_integral_v&lt;decltype(T::value)&gt; &&
      !is_same_v&lt;bool, remove_const_t&lt;decltype(T::value)&gt;&gt; &&
      convertible_to&lt;T, decltype(T::value)&gt; &&
      equality_comparable_with&lt;T, decltype(T::value)&gt; &&
      bool_constant&lt;T() == T::value&gt;::value &&
      bool_constant&lt;static_cast&lt;decltype(T::value)&gt;(T()) == T::value&gt;::value;</del>
  [&hellip;]
}
  </pre>
        </li>
        <li>
          <p>Edit 24.7.3.6.1 <a href="https://eel.is/c++draft/mdspan.mdspan.overview">[mdspan.mdspan.overview]</a> as
            indicated:</p>
          <p>-1- <code>mdspan</code> is a view of a multidimensional array of elements.</p>
          <pre>
namespace std {
  template&lt;class ElementType, class Extents, class LayoutPolicy = layout_right,
           class AccessorPolicy = default_accessor&lt;ElementType&gt;&gt;
  class mdspan {
    [&hellip;]
  };

  template&lt;class CArray&gt;
    requires(is_array_v&lt;CArray&gt; && rank_v&lt;CArray&gt; == 1)
    mdspan(CArray&)
      -> mdspan&lt;remove_all_extents_t&lt;CArray&gt;, extents&lt;size_t, extent_v&lt;CArray, 0&gt;&gt;&gt;;

  template&lt;class Pointer&gt;
    requires(is_pointer_v&lt;remove_reference_t&lt;Pointer&gt;&gt;)
    mdspan(Pointer&&)
      -> mdspan&lt;remove_pointer_t&lt;remove_reference_t&lt;Pointer&gt;&gt;, extents&lt;size_t&gt;&gt;;

  template&lt;class ElementType, class... Integrals&gt;
    requires((is_convertible_v&lt;Integrals, size_t&gt; && ...) && sizeof...(Integrals) > 0)
    explicit mdspan(ElementType*, Integrals...)
      -> mdspan&lt;ElementType, <del>d</del>extents&lt;size_t, <ins><i>maybe-static-ext</i>&lt;Integrals&gt;...</ins><del>sizeof...(Integrals)</del>&gt;&gt;;

  [&hellip;]
}
  </pre>
        </li>
      </ol>
    </ol>
  </div>

  <a name="References"></a>
  <h2>References</h2>

  <dd>
  <dt id="biblio-p2321">[P2630R4]
  <dd>Christian Trott. <code>Submdspan</code>. URL: <a
      href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2630r4.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2630r4.html</a>
  <dt id="biblio-p2321">[P2781R3]
  <dd>Matthias Kretz. <code>std::constexpr_v</code>. URL: <a
      href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2781r3.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2781r3.html</a>
</body>

</html>