<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 930: Access to std::array data as built-in array type</title>
<meta property="og:title" content="Issue 930: Access to std::array data as built-in array type">
<meta property="og:description" content="C++ library issue. Status: NAD">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue930.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#NAD">NAD</a> status.</em></p>
<h3 id="930"><a href="lwg-closed.html#930">930</a>. Access to std::array data as built-in array type</h3>
<p><b>Section:</b> 23.3.3 <a href="https://wg21.link/array">[array]</a> <b>Status:</b> <a href="lwg-active.html#NAD">NAD</a>
 <b>Submitter:</b> Niels Dekker <b>Opened:</b> 2008-11-17 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#array">issues</a> in [array].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#NAD">NAD</a> status.</p>
<p><b>Discussion:</b></p>

<p>
The Working Draft (N2798) allows access to the elements of
<code>std::array</code> by its <code>data()</code> member function:
</p>

<blockquote>

<h5>23.2.1.4 array::data [array.data]</h5>
<pre>
 T *data();
 const T *data() const;
</pre>
<ol><li>
 Returns: elems.
</li></ol>
</blockquote>

<p>
Unfortunately, the result of <code>std::array::data()</code> cannot be bound
to a reference to a built-in array of the type of <code>array::elems</code>.
And <code>std::array</code> provides no other way to get a reference to
<code>array::elems</code>. 
This hampers the use of <code>std::array</code>, for example when trying to
pass its data to a C style API function:
</p>

<pre>
 // Some C style API function. 
 void set_path( char (*)[MAX_PATH] );

 std::array&lt;char,MAX_PATH&gt; path;
 set_path( path.data() );  // error
 set_path( &amp;(path.data()) );  // error
</pre>

 <p>
Another example, trying to pass the array data to an instance of another
C++ class:
</p>

<pre>
 // Represents a 3-D point in space.
 class three_d_point {
 public:
   explicit three_d_point(const double (&amp;)[3]); 
 };

 const std::array&lt;double,3&gt; coordinates = { 0, 1, 2 };
 three_d_point point1( coordinates.data() );  // error.
 three_d_point point2( *(coordinates.data()) );  // error.
</pre>

<p>
A user might be tempted to use <code>std::array::elems</code> instead, but
doing so isn't recommended, because <code>std::array::elems</code> is "for
exposition only".  Note that Boost.Array users might already use
<code>boost::array::elems</code>, as its documentation doesn't explicitly
state that <code>boost::array::elems</code> is for exposition only:
http://www.boost.org/doc/libs/1_36_0/doc/html/boost/array.html
</p>
<p>
I can think of three options to solve this issue:
</p>
<ol><li>
Remove the words "exposition only" from the definition of
<code>std::array::elems</code>, as well as the note saying that "elems is
shown for exposition only."
</li><li>
Change the signature of <code>std::array::data()</code>, so that it would
return a reference to the built-in array, instead of a pointer to its
first element.
</li><li>
Add extra member functions, returning a reference to the built-in array.
</li></ol>
<p>
Lawrence Crowl wrote me that it might be better to leave
<code>std::array::elems</code> "for exposition only", to allow alternate
representations to allocate the array data dynamically.  This might be
of interest to the embedded community, having to deal with very limited
stack sizes.
</p>
<p>
The second option, changing the return type of
<code>std::array::data()</code>, would break backward compatible to current
Boost and TR1 implementations, as well as to the other contiguous
container (<code>vector</code> and <code>string</code>) in a very subtle way.
For example, the following call to <code>std::swap</code> currently swap two
locally declared pointers <code>(data1, data2)</code>, for any container
type <code>T</code> that has a <code>data()</code> member function. When
<code>std::array::data()</code> is changed to return a reference, the
<code>std::swap</code> call may swap the container elements instead.
</p>

<pre>
 template &lt;typename T&gt;
 void func(T&amp; container1, T&amp; container2)
 {
   // Are data1 and data2 pointers or references?
   auto data1 = container1.data();
   auto data2 = container2.data();

   // Will this swap two local pointers, or all container elements?
   std::swap(data1, data2);
 }
</pre>

<p>
The following concept is currently satisfied by all contiguous
containers, but it no longer is for <code>std::array</code>, when
<code>array::data()</code>
is changed to return a reference (tested on ConceptGCC Alpha 7):
</p>

<pre>
 auto concept ContiguousContainerConcept&lt;typename T&gt;
 {
   typename value_type = typename T::value_type;
   const value_type * T::data() const;
 }
</pre>

<p>
Still it's worth considering having <code>std::array::data()</code> return a
reference, because it might be the most intuitive option, from a user's
point of view.  Nicolai Josuttis (who wrote <code>boost::array</code>)
mailed me that he very much prefers this option.
</p>
<p>
Note that for this option, the definition of <code>data()</code> would also
need to be revised for zero-sized arrays, as its return type cannot be a
reference to a zero-sized built-in array.  Regarding zero-sized array,
<code>data()</code> could throw an exception.  Or there could be a partial
specialization of <code>std::array</code> where <code>data()</code> returns
<code>T*</code> or gets removed.
</p>
<p>
Personally I prefer the third option, adding a new member function to
<code>std::array</code>, overloaded for const and non-const access,
returning a reference to the built-in array, to avoid those compatible
issues. I'd propose naming the function <code>std::array::c_array()</code>,
which sounds intuitive to me. Note that <code>boost::array</code> already
has a <code>c_array()</code> member, returning a pointer, but Nicolai told
me that this one is only there for historical reasons. (Otherwise a name
like <code>std::array::native_array()</code> or
<code>std::array::builtin_array()</code> would also be fine with me.) 
According to my proposed resolution, a zero-sized <code>std::array</code> does not need
to have <code>c_array()</code>, while it is still required to have
<code>data()</code> functions.
</p>

<p><i>[
Post Summit:
]</i></p>


<blockquote>

<p>
Alisdair: Don't like p4 suggesting implementation-defined behaviour.
</p>
<p>
Walter: What about an explicit conversion operator, instead of adding
the new member function?
</p>
<p>
Alisdair: Noodling about:
</p>
<blockquote><pre>
template&lt;size_t N, ValueType T&gt;
struct array
{
  T elems[N];

// fantasy code starts here

// crazy decltype version for grins only
//requires True&lt;(N&gt;0)&gt;
//explict operator decltype(elems) &amp; () { return elems; }

// conversion to lvalue ref
requires True&lt;(N&gt;0)&gt;
explict operator T(&amp;)[N] () &amp; { return elems; }

// conversion to const lvalue ref
requires True&lt;(N&gt;0)&gt;
explict operator const T(&amp;)[N] () const &amp; { return elems; }

// conversion to rvalue ref using ref qualifiers
requires True&lt;(N&gt;0)&gt;
explict operator T(&amp;&amp;)[N] () &amp;&amp; { return elems; }

// fantasy code ends here

explicit operator bool() { return true; }
};
</pre></blockquote>

<p>
This seems legal but odd. Jason Merrill says currently a CWG issue 613
on the non-static data member that fixes the error that current G++
gives for the non-explicit, non-conceptualized version of this. Verdict
from human compiler: seems legal.
</p>
<p>
Some grumbling about zero-sized arrays being allowed and supported.
</p>
<p>
Walter: Would this address the issue? Are we inclined to go this route?
</p>
<p>
Alan: What would usage look like?
</p>
<blockquote><pre>
// 3-d point in space
struct three_d_point
{
  explicit three_d_point(const double (&amp;)[3]);
};

void sink(double*);

const std::array&lt;double, 3&gt; coordinates = { 0, 1, 2 };
three_d_point point1( coordinates.data() ); //error
three_d_point point2( *(coordinates.data()) ); // error
three_d_point point3( coordinates ); // yay!

sink(cooridinates); // error, no conversion
</pre></blockquote>

<p>
Recommended Open with new wording. Take the required clause and add the
explicit conversion operators, not have a <code>typedef</code>. At issue still is use
<code>decltype</code> or use <code>T[N]</code>. In favour of using <code>T[N]</code>, even though use of
<code>decltype</code> is specially clever.
</p>

</blockquote>

<p><i>[
Post Summit, further discussion in the thread starting with c++std-lib-23215.
]</i></p>


<p><i>[
2009-07 post-Frankfurt (Saturday afternoon group):
]</i></p>


<blockquote>
<p>
The idea to resolve the issue by adding explicit conversion operators
was abandoned, because it would be inconvenient to use, especially when
passing the array to a template function, as mentioned by Daniel. So we
reconsidered the original proposed resolution, which appeared
acceptable, except for its proposed changes to 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a>, which
allowed <code>c_array_type</code> and <code>c_array()</code> to be absent for a zero-sized array.
Alisdair argued that such wording would disallow certain generic use
cases. New wording for 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a> was agreed upon (Howard: and
is reflected in the proposed resolution).
</p>
<p>
Move to Review
</p>
</blockquote>

<p><i>[
2009-07-31 Alisdair adds:
]</i></p>


<blockquote>
<p>
I will be unhappy voting the proposed resolution for 930 past review
until we have implementation experience with reference qualifiers. 
Specifically, I want to understand the impact of the missing overload
for <code>const &amp;&amp;</code> (if any.)
</p>

<p>
If we think the issue is important enough it might be worthwhile
stripping the ref qualifiers for easy progress next meeting, and opening
yet another issue to put them back with experience.
</p>

<p>
Recommend deferring any decision on splitting the issue until we get LWG
feedback next meeting - I may be the lone dissenting voice if others are
prepared to proceed without it.
</p>
</blockquote>

<p><i>[
2009-10 Santa Cruz:
]</i></p>


<blockquote><p>
Mark as NAD. There was not enough consensus that this was sufficiently
useful. There are known other ways to do this, such as small inline
conversion functions.
</p></blockquote>



<p id="res-930"><b>Proposed resolution:</b></p>
<p>
Add to the template definition of array, 23.3.3 <a href="https://wg21.link/array">[array]</a>/3:
</p>

<blockquote>
<pre><ins>
typedef T c_array_type[N];
c_array_type &amp; c_array() &amp;;
c_array_type &amp;&amp; c_array() &amp;&amp;;
const c_array_type &amp; c_array() const &amp;;
</ins>
</pre>
</blockquote>

<p>
Add the following subsection to 23.3.3 <a href="https://wg21.link/array">[array]</a>, after  [array.data]:
</p>

<blockquote>
<h5><ins>23.2.1.5 array::c_array [array.c_array]</ins></h5>
    <pre><ins>
c_array_type &amp; c_array() &amp;;
c_array_type &amp;&amp; c_array() &amp;&amp;;
const c_array_type &amp; c_array() const &amp;;
</ins></pre>
<blockquote>
<p>
<ins><i>Returns:</i> <code>elems</code>.</ins>
</p>
</blockquote>

</blockquote>



<p>
Change Zero sized arrays 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a>:
</p>

<blockquote>

<p>-2- ...</p>

<p><ins>
The type <code>c_array_type</code> is unspecified for a zero-sized array.
</ins></p>

<p>
-3- The effect of calling <ins><code>c_array()</code>,</ins> <code>front()</code><ins>,</ins> or
<code>back()</code> for a zero-sized array is implementation defined.
</p>
</blockquote>






</body>
</html>
