Document number:  N2930=09-0120
Date: 2009-07-16
Project: Programming Language C++, Library Working Group
Reply-to: Douglas Gregor <doug.gregor at gmail.com>
Beman Dawes <bdawes at acm.org>

Range-Based For Loop Wording (Without Concepts)

Introduction
Summary of proposed changes
Proposed wording
Acknowledgements

Introduction

With the removal of concepts from the C++0x working paper, the range-based for loop requires new wording that does not rely on concepts. This proposal provides such wording. It also addresses CD1 comments UK 78 and UK 79, whih essentially ask that the range-based for statement "just work" for arrays (without requiring the user to include a header), e.g.,

[ Example:

int array[5] = { 1, 2, 3, 4, 5 };
for (int& x : array)
  x *= 2;

—end example ]

Summary of proposed changes

Proposed wording

The wording here is based on the current working paper once the concepts proposals and previous range-based for loop (N2778) have been removed. The first two sections have an editorial note that specifies that the text of the current working paper and the net result of removing those previous proposals will be the same. Text to be removed is shown in red, text to be added is shown in green.  Underbars are not shown for additions because the many underscores in the affected text become unreadable.

Modify paragraph 4 of 3.3.3 [basic.scope.local] as follows:

  1. Names declared in the for-init-statement, the for-range-declaration, and in the condition of if, while, for, and switch statements are local to the if, while, for, or switch statement (including the controlled statement), and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for the if statement, any of the outermost blocks) of the controlled statement; see 6.4.

Editorial Note: the wording above is identical to what is in the current working paper. It is given here for completeness.

Modify paragraph 1 of 6.5 [stmt.iter] as follows:

  1. Iteration statements specify looping.
    iteration-statement:
         while ( condition ) statement
         do statement while ( expression ) ;
         for ( for-init-statement conditionopt ; expressionopt ) statement
         for ( for-range-declaration : expression ) statement
    for-init-statement:
         expression-statement
         simple-declaration
    for-range-declaration:
         type-specifier-seq attribute-specifieropt declarator
    [ Note: a for-init-statement ends with a semicolon. -- end note ]

Editorial Note: the wording above is identical to what is in the current working paper. It is given here for completeness.

Add a new section 6.5.4 Range-based for statement [stmt.ranged], as indicated:

The range-based for statement

for ( for-range-declaration : expression ) statement

 is equivalent to

{
  auto && __range = ( expression );
  for (auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) {
    for-range-declaration = *__begin;
    statement
  }
}

where __range, __begin, and __end are variables defined for exposition only, _RangeT is the type of the expression, and begin-expr and end-expr are determined as follows:

[ Example:

int array[5] = { 1, 2, 3, 4, 5 };
for (int& x : array)
  x *= 2;

--end example]

Modify the header <initializer_list> synopsis in section 18.9 Initializer lists [support.initlist] by adding the following to the synopsis:

namespace std {
  // ...

  // 18.9.3 initializer list range access [support.initlist.range]
  template<typename E> const E* begin(initializer_list<E> il);
  template<typename E> const E* end(initializer_list<E> il);
}

Add a new section 18.9.3 initializer list range access [support.initlist.range], with the following text:

  template<typename E> const E* begin(initializer_list<E> il);
  1. Returns: il.begin()
  template<typename E> const E* end(initializer_list<E> il);
  1. Returns: il.end()

Modify the section 20.2 Header <utility> synopsis by adding the following to the synopsis:

  // 20.2.3 pair range access [pair.range]
  template<typename InputIterator>
    InputIterator begin(const std::pair<InputIterator, InputIterator>& p);
  template<typename InputIterator>
    InputIterator end(const std::pair<InputIterator, InputIterator>& p);

Add a new section 20.2.3 pair range access [pair.range], with the following text:

template<typename InputIterator>
  InputIterator begin(const std::pair<InputIterator, InputIterator>& p);
  1. Returns: p.first
template<typename InputIterator>
  InputIterator end(const std::pair<InputIterator, InputIterator>& p);
  1. Returns: p.second

Modify the section 20.5.1 Header <tuple> synopsis by adding the following to the synopsis:

  // 20.5.2.8 tuple range access [tuple.range]
  template<typename InputIterator>
    InputIterator begin(const std::tuple<InputIterator, InputIterator>& t);
  template<typename InputIterator>
    InputIterator end(const std::tuple<InputIterator, InputIterator>& t);

Add a new section 20.5.2.8 tuple range access [tuple.range], with the following text:

template<typename InputIterator>
  InputIterator begin(const std::tuple<InputIterator, InputIterator>& t);
  1. Returns: std::get<0>(t)
template<typename InputIterator>
  InputIterator end(const std::tuple<InputIterator, InputIterator>& t);
  1. Returns: std::get<1>(t)

Modify the section 24.3 Header <iterator> synopsis [iterator.syn] by adding the following at the end of the synopsis:

  // 24.7 range access [iterator.range]
  template<typename C> auto begin(C& c) -> decltype(c.begin());
  template<typename C> auto begin(const C& c) -> decltype(c.begin());
  template<typename C> auto end(C& c) -> decltype(c.end());
  template<typename C> auto end(const C& c) -> decltype(c.end());
  template<typename T, size_t N> T* begin(T (&array)[N]);
  template<typename T, size_t N> T* end(T (&array)[N]);

Add a new section 24.7 range access [iterator.range] containing the following:

  1. In addition to being available via inclusion of the <iterator> header, the function templates in [iterator.range] are also available when any of the following headers are included: <array>, <deque>, <forward_list>, <list>, <map>, <regex>, <set>, <string>, <unordered_map>, <unordered_set>, or <vector>.
template<typename C> auto begin(C& c) -> decltype(c.begin());
template<typename C> auto begin(const C& c) -> decltype(c.begin());
  1. Returns: c.begin()
template<typename C> auto end(C& c) -> decltype(c.end());
template<typename C> auto end(const C& c) -> decltype(c.end());
  1. Returns: c.end()
template<typename T, size_t N> T* begin(T (&array)[N]);
  1. Returns: array
template<typename T, size_t N> T* end(T (&array)[N]);
  1. Returns: array + N

Modify the section 24.6.1 Header <valarray> synopsis [valarray.syn] by adding the following at the end of the synopsis:

template<typename T> unspecified-1 begin(valarray<T>& v);
template<typename T> unspecified-2 begin(const valarray<T>& v);
template<typename T> unspecified-1 end(valarray<T>& v);
template<typename T> unspecified-2 end(const valarray<T>& v);

Add a new section 26.6.10 valarray range access [valarray.range] containing the following:

  1. In the begin and end function templates that follow, unspecified-1 is a type that meets the requirements of a mutable random access iterator ([random.access.iterators]) whose value_type is the template parameter T and whose reference type is T&. unspecified-2 is a type that meets the requirements of a constant random access iterator ([random.access.iterators]) whose value_type is the template parameter T and whose reference type is const T&.
template<typename T> unspecified-1 begin(valarray<T>& v);
template<typename T> unspecified-2 begin(const valarray<T>& v);
  1. Returns: an iterator referencing the first value in the numeric array
template<typename T> unspecified-1 end(valarray<T>& v);
template<typename T> unspecified-2 end(const valarray<T>& v);
  1. Returns: an iterator referencing one past the last value in the numeric array

Add #include <initializer_list> to the synopsis for the following headers:

<string> 21.3 String classes [string.classes]
<array>, <deque>, <forward_list>, <list>, <queue>, <stack>, and <vector> 23.3 Sequence containers [sequences]
<map> and <set> 23.4 Associative containers [associative]
<unordered_map> and <unordered_set> 23.5 Unordered associative containers [unord]
<algorithm> 25.2 Header <algorithm> synopsis [algorithms.syn]
<random> 26.5.1 Header <random> synopsis [rand.synopsis]
<valarray> 26.6.1 Header <valarray> synopsis [valarray.syn]
<regex> 28.4 Header <regex> synopsis [re.syn]

Acknowledgements

James Widman identified several deficiencies in drafts of this proposal and provided fixes for them.

Steve Adamczyk, Alberto Ganesh Barbati, Walter E Brown, Gabriel Dos Reis, Daniel Krügler, Jens Maurer, Thorsten Ottosen, Bjarne Stroustrup, Herb Sutter, and James Widman participated in discussions, reviewed drafts, and suggested improvements.