title: Why does std::cbegin() not call .cbegin() on the container?
body: <p>The following code fails the static assertion:</p>
  
  <pre><code>#include &lt;gsl/span&gt;
  #include &lt;iterator&gt;
  #include &lt;type_traits&gt;
  
  int main()
  {
      int theArr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
      gsl::span&lt;int&gt; theSpan{ theArr, std::size(theArr) };
  
      using std::cbegin;
      auto it1 = cbegin(theSpan);
      auto it2 = theSpan.cbegin();
      static_assert(std::is_same_v&lt;decltype(it1), decltype(it2)&gt;);
  }
  </code></pre>
  
  <p>This fails because <code>std::cbegin()</code> calls the <code>.begin()</code> method on a const ref of the container. For standard-defined containers, this returns a <code>const_iterator</code>, which is the same type that <code>.cbegin()</code> returns. However, <code>gsl::span</code> is a bit unique because it models a sort of "borrow type". A <code>const gsl::span</code> behaves like a const pointer; the span itself is const, but what it points-to is not const. Hence, the <code>.begin()</code> method on a <code>const gsl::span</code> still returns a non-const iterator, whereas explicitly calling <code>.cbegin()</code> returns a const iterator.</p>
  
  <p>I'm curious as to why <code>std::cbegin()</code> was not defined as invoking <code>.cbegin()</code> on the container (which all standard containers seem to implement) to account for cases such as this.</p>
  
  <p>This is somewhat related to: <a href="https://stackoverflow.com/questions/29486309/why-does-stdcbegin-return-the-same-type-as-stdbegin">Why does std::cbegin return the same type as std::begin</a></p>