2128. Absence of global functions cbegin/cend

Section: 24.2 [iterator.synopsis], 24.7 [iterator.range] Status: C++14 Submitter: Dmitry Polukhin Opened: 2012-01-23 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [iterator.synopsis].

View all issues with C++14 status.

Discussion:

All standard containers support cbegin/cend member functions but corresponding global functions are missing. Proposed resolution it to add global cbegin/cend functions by analogy with global begin/end functions. This addition will unify things for users.

[2012, Kona]

STL: Range-based for loops do not use global begin/end (anymore).

Alisdair: We will have to make sure these will be available through many headers.

STL: Do this, including r and cr. This won't add any additional work.

Matt: Users will find it strange if these are not all available.

Alisdair: Should we have these available everywhere begin/end are available?

Marshall: Yes. Not any extra work.

Howard: Adding all of these means we need all of <iterator>.

STL: We already need it all.

Matt: We have to be careful what we are requiring if we include the r versions.

Jeffrey: If we include r, should they adapt if the container does not define reverse iteration?

STL: No. No special behavior. Should fail to compile. Up to user to add the reverse code--it's easy.

Howard: Anyway it will SFINAE out.

Alisdair: Error messages due to SFINAE are harder to understand than simple failure to compile.

STL: Agrees that SFINAE makes error messages much worse.

Action: STL to provide additional wording for the r variants. Move to Review once that wording is availalbe.

[ 2013-04-14 STL provides rationale and improved wording ]

Step 1: Implement std::cbegin/cend() by calling std::begin/end(). This has numerous advantages:

Step 2: Like std::begin/end(), implement std::rbegin/rend() by calling c.rbegin/rend(). Note that C++98/03 had the Reversible Container Requirements.

Step 3: Also like std::begin/end(), provide overloads of std::rbegin/rend() for arrays.

Step 4: Provide overloads of std::rbegin/rend() for initializer_list, because it lacks rbegin/rend() members. These overloads follow 17.10.5 [support.initlist.range]'s signatures. Note that because these overloads return reverse_iterator, they aren't being specified in <initializer_list>.

Step 5: Like Step 1, implement std::crbegin/crend() by calling std::rbegin/rend().

Original wording saved here:

This wording is relative to N3337.

  1. In 24.2 [iterator.synopsis], header iterator synopsis, add the following declarations:

    namespace std {
      […]
      // 24.6.5, range access:
      template <class C> auto begin(C& c) -> decltype(c.begin());
      template <class C> auto begin(const C& c) -> decltype(c.begin());
      template <class C> auto end(C& c) -> decltype(c.end());
      template <class C> auto end(const C& c) -> decltype(c.end());
      template <class C> auto cbegin(const C& c) -> decltype(c.cbegin());
      template <class C> auto cend(const C& c) -> decltype(c.cend());
      template <class T, size_t N> T* begin(T (&array)[N]);
      template <class T, size_t N> T* end(T (&array)[N]);
      template <class T, size_t N> const T* cbegin(T (&array)[N]);
      template <class T, size_t N> const T* cend(T (&array)[N]);
    }
    
  2. In 24.7 [iterator.range] after p5 add the following series of paragraphs:

    template <class C> auto cbegin(const C& c) -> decltype(c.cbegin());
    

    -?- Returns: c.cbegin().

    template <class C> auto cend(const C& c) -> decltype(c.cend());
    

    -?- Returns: c.cend().

    template <class T, size_t N> const T* cbegin(T (&array)[N]);
    

    -?- Returns: array.

    template <class T, size_t N> const T* cend(T (&array)[N]);
    

    -?- Returns: array + N.

[2013-04-18, Bristol]

Proposed resolution:

This wording is relative to N3485.

  1. In 24.2 [iterator.synopsis], header iterator synopsis, add the following declarations:

    namespace std {
      […]
      // 24.6.5, range access:
      template <class C> auto begin(C& c) -> decltype(c.begin());
      template <class C> auto begin(const C& c) -> decltype(c.begin());
      template <class C> auto end(C& c) -> decltype(c.end());
      template <class C> auto end(const C& c) -> decltype(c.end());
      template <class T, size_t N> T* begin(T (&array)[N]);
      template <class T, size_t N> T* end(T (&array)[N]);
      template <class C> auto cbegin(const C& c) -> decltype(std::begin(c));
      template <class C> auto cend(const C& c) -> decltype(std::end(c));
      template <class C> auto rbegin(C& c) -> decltype(c.rbegin());
      template <class C> auto rbegin(const C& c) -> decltype(c.rbegin());
      template <class C> auto rend(C& c) -> decltype(c.rend());
      template <class C> auto rend(const C& c) -> decltype(c.rend());
      template <class T, size_t N> reverse_iterator<T*> rbegin(T (&array)[N]);
      template <class T, size_t N> reverse_iterator<T*> rend(T (&array)[N]);
      template <class E> reverse_iterator<const E*> rbegin(initializer_list<E> il);
      template <class E> reverse_iterator<const E*> rend(initializer_list<E> il);
      template <class C> auto crbegin(const C& c) -> decltype(std::rbegin(c));
      template <class C> auto crend(const C& c) -> decltype(std::rend(c));
    }
    
  2. At the end of 24.7 [iterator.range], add:

    template <class C> auto cbegin(const C& c) -> decltype(std::begin(c));
    

    -?- Returns: std::begin(c).

    template <class C> auto cend(const C& c) -> decltype(std::end(c));
    

    -?- Returns: std::end(c).

    template <class C> auto rbegin(C& c) -> decltype(c.rbegin());
    template <class C> auto rbegin(const C& c) -> decltype(c.rbegin());
    

    -?- Returns: c.rbegin().

    template <class C> auto rend(C& c) -> decltype(c.rend());
    template <class C> auto rend(const C& c) -> decltype(c.rend());
    

    -?- Returns: c.rend().

    template <class T, size_t N> reverse_iterator<T*> rbegin(T (&array)[N]);
    

    -?- Returns: reverse_iterator<T*>(array + N).

    template <class T, size_t N> reverse_iterator<T*> rend(T (&array)[N]);
    

    -?- Returns: reverse_iterator<T*>(array).

    template <class E> reverse_iterator<const E*> rbegin(initializer_list<E> il);
    

    -?- Returns: reverse_iterator<const E*>(il.end()).

    template <class E> reverse_iterator<const E*> rend(initializer_list<E> il);
    

    -?- Returns: reverse_iterator<const E*>(il.begin()).

    template <class C> auto crbegin(const C& c) -> decltype(std::rbegin(c));
    

    -?- Returns: std::rbegin(c).

    template <class C> auto crend(const C& c) -> decltype(std::rend(c));
    

    -?- Returns: std::rend(c).