<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3255: span's array constructor is too strict</title>
<meta property="og:title" content="Issue 3255: span's array constructor is too strict">
<meta property="og:description" content="C++ library issue. Status: C++20">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3255.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++20">C++20</a> status.</em></p>
<h3 id="3255"><a href="lwg-defects.html#3255">3255</a>. <code>span</code>'s <code>array</code> constructor is too strict</h3>
<p><b>Section:</b> 23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a> <b>Status:</b> <a href="lwg-active.html#C++20">C++20</a>
 <b>Submitter:</b> Jean Guegant &amp; Barry Revzin <b>Opened:</b> 2019-08-10 <b>Last modified:</b> 2021-02-25</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#span.cons">issues</a> in [span.cons].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++20">C++20</a> status.</p>
<p><b>Discussion:</b></p>
<p>
<b>Barry Revzin:</b>
<p/>
From <a href="https://stackoverflow.com/q/57444188/2069064">StackOverflow</a>:
<p/>
This compiles:
</p>
<blockquote><pre>
std::vector&lt;int*&gt; v = {nullptr, nullptr};
std::span&lt;const int* const&gt; s{v};
</pre></blockquote>
<p>
This does not:
</p>
<blockquote><pre>
std::array&lt;int*, 2&gt; a = {nullptr, nullptr};
std::span&lt;const int* const&gt; s{a};
</pre></blockquote>
<p>
The problem is that <code>span</code>'s constructors include
</p>
<ul>
<li><p>A constructor template that takes any <code>Container</code> that is neither a raw array nor a <code>std::array</code></p></li>
<li><p>A constructor template that takes an <code>array&lt;value_type, N&gt;&amp;</code></p></li>
<li><p>A constructor template that takes a <code>const array&lt;value_type, N&gt;&amp;</code></p></li>
</ul>
<p>
So the first is excluded, and the other two don't match. We can change the array constructor templates to take an
<code>array&lt;T, N&gt;</code> with the requirement that <code>T(*)[]</code> is convertible to <code>ElementType(*)[]</code>?
<p/>
<b>Jean Guegant:</b>
<p/>
It is impossible to create a <code>std::span</code> from a <code>std::array&lt;const T, X&gt;</code> given the current
set of constructors of <code>std::span</code> (23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a>):
</p>
<blockquote><pre>
std::array&lt;const int, 4&gt; a = {1, 2, 3, 4};
std::span&lt;const int&gt; s{a}; <i>// No overload can be found.</i>
std::span s{a}; <i>// CTAD doesn't help either.</i>
</pre></blockquote>
<p>
Both constructors accepting a <code>std::array</code> (23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a> p11) require the first template
parameter of the <code>std::array</code> parameter to be <code>value_type</code>:
</p>
<blockquote><pre>
template&lt;size_t N&gt; constexpr span(array&lt;value_type, N&gt;&amp; arr) noexcept;
template&lt;size_t N&gt; constexpr span(const array&lt;value_type, N&gt;&amp; arr) noexcept;
</pre></blockquote>
<p>
<code>value_type</code> being defined as <code>remove_cv_t&lt;ElementType&gt;</code> &mdash; this constrains the first
template parameter not to be <code>const</code>.
<p/>
Both constructors accepting a generic <code>Container</code> (23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a> p14) have a
constraint &mdash; (p14.3) <code>Container</code> is not a specialization of <code>array</code> &mdash;
rejecting <code>std::array</code>.
<p/>
While you can call <code>std::array&lt;const T, X&gt;::data</code> and <code>std::array&lt;const T, X&gt;::size</code>
to manually create a <code>std::span</code>, we should, in my opinion, offer a proper overload for this scenario.
Two reasons came to my mind:
</p>
<ol>
<li><p><code>std::span</code> handles C-arrays and <code>std::arrays</code> in an asymmetric way. The constructor
taking a C-array (23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a> p11) is using <code>element_type</code> and as such can work with
<code>const T</code>:</p>
<blockquote><pre>
const int a[] = {1, 2, 3, 4};
std::span&lt;const int&gt; s{a}; <i>// It works</i>
</pre></blockquote>
<p>
If a user upgrades her/his code from C-arrays to a <code>std::array</code>s and literally take the type
<code>const T</code> and use it as the first parameter of <code>std::array</code>, he/she will face an error.
</p>
</li>
<li><p>Even if the user is aware that <code>const std::array&lt;T, X&gt;</code> is more idiomatic than
<code>std::array&lt;const T, X&gt;</code>, the second form may appear in the context of template
instantiation.</p></li>
</ol>
<p>
At the time this issue is written <code>gls::span</code>, from which <code>std::span</code> is partly based on,
does not suffer from the same issue: Its constructor taking a generic <code>const Container&amp;</code> does
not constraint the <code>Container</code> not to be a <code>std::array</code> (although its constructor taking
a generic <code>Container&amp;</code> does). For the users willing to upgrade from <code>gsl::span</code> to
<code>std::span</code>, this could be a breaking change.
</p>

<p><i>[2019-09-01 Priority set to 2 based on reflector discussion]</i></p>


<p><i>[2020-02-13 Tim updates PR]</i></p>

<p>
The previous PR's change to the raw array constructor is both 1) unnecessary and 2) incorrect; it prevents
<code>span&lt;const int&gt;</code> from being initialized with an <code>int[42]</code> xvalue.
</p>

<strong>Previous resolution: [SUPERSEDED]</strong>

<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/n4830">N4830</a>.</p>

<blockquote class="note">
<p>
The only change is to make the constructors templated on the element type of the array as well.
We already have the right constraints in place. It's just that the 2nd constraint is trivially
satisfied today by the raw array constructor and either always or never satisfied by the <code>std::array</code> one.
</p>
</blockquote>

<ol>
<li><p>Modify 23.7.2.2.1 <a href="https://wg21.link/span.overview">[span.overview]</a>, class template <code>span</code> synopsis, as indicated:</p>

<blockquote>
<pre>
template&lt;class ElementType, size_t Extent = dynamic_extent&gt;
class span {
public:
  [&hellip;]
  <i>// 23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a>, constructors, copy, and assignment</i>
  constexpr span() noexcept;
  constexpr span(pointer ptr, index_type count);
  constexpr span(pointer first, pointer last);
  template&lt;<ins>class T,</ins> size_t N&gt;
    constexpr span(<ins>T</ins><del>element_type</del> (&amp;arr)[N]) noexcept;
  template&lt;<ins>class T,</ins> size_t N&gt;
    constexpr span(array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
  template&lt;<ins>class T,</ins> size_t N&gt;
    constexpr span(const array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
  [&hellip;]
};
</pre>
</blockquote>
</li>

<li><p>Modify 23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a> as indicated:</p>

<blockquote>
<pre>
template&lt;<ins>class T,</ins> size_t N&gt;
  constexpr span(<ins>T</ins><del>element_type</del> (&amp;arr)[N]) noexcept;
template&lt;<ins>class T,</ins> size_t N&gt;
  constexpr span(array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
template&lt;<ins>class T,</ins> size_t N&gt;
  constexpr span(const array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
</pre>
<blockquote>
<p>
-11- <i>Constraints:</i>
</p>
<ol style="list-style-type: none">
<li><p>(11.1) &mdash; <code>extent == dynamic_extent || N == extent</code> is <code>true</code>, and</p></li>
<li><p>(11.2) &mdash; <code>remove_pointer_t&lt;decltype(data(arr))&gt;(*)[]</code> is convertible to <code>ElementType(*)[]</code>.</p></li>
</ol>
<p>
-12- <i>Effects:</i> Constructs a <code>span</code> that is a view over the supplied array.
<p/>
-13- <i>Ensures:</i> <code>size() == N &amp;&amp; data() == data(arr)</code> <ins>is <code>true</code></ins>.
</p>
</blockquote>
</blockquote>
</li>

</ol>
</blockquote>

<p><i>[2020-02 Status to Immediate on Thursday night in Prague.]</i></p>



<p id="res-3255"><b>Proposed resolution:</b></p>
<p>This wording is relative to <a href="https://wg21.link/n4849">N4849</a>.</p>
<ol>
<li><p>Modify 23.7.2.2.1 <a href="https://wg21.link/span.overview">[span.overview]</a>, class template <code>span</code> synopsis, as indicated:</p>

<blockquote>
<pre>
template&lt;class ElementType, size_t Extent = dynamic_extent&gt;
class span {
public:
  [&hellip;]
  <i>// 23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a>, constructors, copy, and assignment</i>
  constexpr span() noexcept;
  [&hellip;]
  template&lt;size_t N&gt;
    constexpr span(element_type (&amp;arr)[N]) noexcept;
  template&lt;<ins>class T,</ins> size_t N&gt;
    constexpr span(array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
  template&lt;<ins>class T,</ins> size_t N&gt;
    constexpr span(const array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
  [&hellip;]
};
</pre>
</blockquote>
</li>

<li><p>Modify 23.7.2.2.2 <a href="https://wg21.link/span.cons">[span.cons]</a> as indicated:</p>

<blockquote>
<pre>
template&lt;size_t N&gt;
  constexpr span(element_type (&amp;arr)[N]) noexcept;
template&lt;<ins>class T,</ins> size_t N&gt;
  constexpr span(array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
template&lt;<ins>class T,</ins> size_t N&gt;
  constexpr span(const array&lt;<ins>T</ins><del>value_type</del>, N&gt;&amp; arr) noexcept;
</pre>
<blockquote>
<p>
-11- <i>Constraints:</i>
</p>
<ol style="list-style-type: none">
<li><p>(11.1) &mdash; <code>extent == dynamic_extent || N == extent</code> is <code>true</code>, and</p></li>
<li><p>(11.2) &mdash; <code>remove_pointer_t&lt;decltype(data(arr))&gt;(*)[]</code> is convertible to <code>ElementType(*)[]</code>.</p></li>
</ol>
<p>
-12- <i>Effects:</i> Constructs a <code>span</code> that is a view over the supplied array.
<p/>
-13- <i>Postconditions:</i> <code>size() == N &amp;&amp; data() == data(arr)</code> <ins>is <code>true</code></ins>.
</p>
</blockquote>
</blockquote>
</li>

</ol>





</body>
</html>
