This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.

### 2128. Absence of global functions `cbegin/cend`

Section: 23.2 [iterator.synopsis], 23.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:

- It automatically works with arrays, which is the whole point of these non-member functions.
- It works with C++98/03-era user containers, written before `cbegin/cend()` members were invented.
- It works with `initializer_list`, which is extremely minimal and lacks `cbegin/cend()` members.
- 22.2.1 [container.requirements.general] guarantees that this is equivalent to calling cbegin/cend() members.

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 23.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 23.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 23.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 23.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)`.