Wording for range-based for-loop (revision 3)

Author: Thorsten Ottosen
Contact: nesotto@cs.aau.dk
Advisor:Lawrence Crowl, Douglas Gregor and Jens Maurer
Organizations:Department of Computer Science, Aalborg University
Date: 2007-09-09
Number:WG21/N2394 and J16/07-0254
Working Group:Core

Abstract

This paper provides wording for the new range-based for-loop previously described in n1868, n1961, n2049, n2196 and n2243.

Table of Contents

Introduction

This document provides wording for a concept-based implementation of the range-based for loop. The proposal is implemented in the latest version of Douglas Gregors Concept GCC.

Each numbered section below describes a new section for the standard or modifications to an existing section. Comments are written in bold up front and are not part of the wording.

The author would like to thank Lawrence Crowl, Steve Adamczyk and Douglas Gregor for their help with the first revisions. Special thanks goes to Jens Maurer for his help with this revision. Any mistake is the responsibility of the author.

Changes from n2243

Changes from n2196

Missing parts

The layout of concept headers is not yet finalized. This will only affect the library wording in minor ways and so the wording is included with any reference to the exact section in the standard.

Wording

3.3.2 Local scope

Modify paragraph 4 as indicated:

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 stmt.select.

6.5 Iteration statements

Modify paragraph 1 as indicated:

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 declarator

6.5.4 The range-based for statement

Add the following new section:

1 The range-based for statement

for ( for-range-declaration : expression ) statement

is equivalent to

{
     auto && __range = ( expression );
    
     for ( auto __begin = std::Range<_RangeT>::begin(__range),
                  __end = std::Range<_RangeT>::end(__range);
          __begin != __end;
          ++__begin )
     {
         for-range-declaration = *__begin;
         statement
     }    
}

where __range, __begin and __end are variables defined for exposition only, and _RangeT is the type of the expression.

[Example:

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

-- end example]

2 If the header <iterator_concept> is not included prior to a use of the range-based for statement, the program is ill-formed.

7.1.5.4 auto specifier

Modify paragraph 3 as indicated:

3 This use of auto is allowed when declaring objects in a block (6.3 stmt.block), in namespace scope (3.3.5 basic.scope.namespace), and in a for-init-statement (6.5.3 stmt.for), and in a for-range-declaration (6.5.3 stmt.for).

xx.x Range concept

Add the following to the section that describes header <iterator_concept>:

1 A class or a built-in type T satisfies the requirement of a range if it meets the syntactic and semantic requirements of the Range concept.

concept Range< typename T >
{
    InputIterator iterator;
    iterator begin( T& );
    iterator end( T& );
};

2 For an object t of a type T conforming to the Range concept, [Range<T>::begin(t),Range<T>::end(t)) designates a valid range (24.1.7).

3 Any object of a type conforming to the Range concept can be used with the range-based for statement (6.5.4)

xx.y Header <iterator_concept> synopsis

Add the following new section:

namespace std 
{
  template< class T, size_t N >
  concept_map Range< T[N] >
  { see below }
  
  template<Container C> 
  concept_map Range<C> 
  { see below }
 
  template<Container C> 
  concept_map Range<const C> 
  { see below } 
}

xx.z Range concept maps

Add the following new section:

1 Array objects can be used with the range-based for statement due to the following concept map:

template< class T, size_t N >
concept_map Range< T[N] >
{
    typedef T* iterator;
    iterator begin( T(&a)[N] );
    iterator end( T(&a)[N] );
};
  • iterator begin( T(&a)[N] );

2 Returns: a

  • iterator end( T(&a)[N] );

3 Returns: a + N

4 Any object of a type that meets the requirements of the Container concept can be used with the range-based for statement due to the following concept maps:

template<Container C> 
concept_map Range<C> 
{ 
    typedef C::iterator iterator; 
    iterator begin( C& c );
    iterator end( C& c );
};

template<Container C> 
concept_map Range<const C> 
{ 
    typedef C::const_iterator iterator; 
    iterator begin( const C& c );
    iterator end( const C& c );
};
  • iterator begin( C& c );
  • iterator begin( const C& c );

5 Returns: c.begin();

  • iterator end( C& c );
  • iterator end( const C& c );

6 Returns: c.end()

18.8 Header <initializer_list>

Add the following to the synopsis:

template<typename T>
concept_map Range< initializer_list<T> >
{ *see below* }

template<typename T>
concept_map Range< const initializer_list<T> >
{ *see below* }

18.8.1 Initializer list concept maps

Add the following new section that describes <initializer_list>:

1 Initializer lists can be used with the range-based for statement due to the following concept maps:

template<typename T>
concept_map Range< initializer_list<T> >
{
    typedef const T* iterator;

    iterator begin( initializer_list<T>& r );
    iterator end( initializer_list<T>& r );
}

template<typename T>
concept_map Range< const initializer_list<T> >
{
    typedef const T* iterator;

    iterator begin( const initializer_list<T>& r );
    iterator end( const initializer_list<T>& r );
}
  • iterator begin( initializer_list<T>& r );
  • iterator begin( const initializer_list<T>& r );

2 Returns: r.begin()

  • iterator end( initializer_list<T>& r );
  • iterator end( const initializer_list<T>& r );

3 Returns: return r.end()

20.2 Header <utility> synopsis

Add the following to the synopsis:

template<InputIterator Iter> 
concept_map Range< pair<Iter,Iter> > 
{ see below }

template<InputIterator Iter> 
concept_map Range< const pair<Iter,Iter> > 
{ see below }

20.2.3 pair concept maps

Add the following new section:

1 A pair object of two iterators can be used with the range-based for statement due to the following concept maps:

template<InputIterator Iter> 
concept_map Range< pair<Iter,Iter> > 
{ 
    typedef Iter iterator; 
    Iter begin( pair<Iter,Iter>& p );
    Iter end( pair<Iter,Iter>& p );
};

template<InputIterator Iter> 
concept_map Range< const pair<Iter,Iter> > 
{ 
    typedef Iter iterator; 
    Iter begin( const pair<Iter,Iter>& p );
    Iter end( const pair<Iter,Iter>& p );
};
  • Iter begin( pair<Iter,Iter>& p );
  • Iter begin( const pair<Iter,Iter>& p );

2 Returns: p.first

  • Iter end( pair<Iter,Iter>& p );
  • Iter end( const pair<Iter,Iter>& p );

3 Returns: p.second

20.3 Header <tuple> synopsis

Add the following to the synopsis:

template<InputIterator Iter> 
concept_map Range< tuple<Iter,Iter> > 
{ see below }

template<InputIterator Iter> 
concept_map Range< const tuple<Iter,Iter> > 
{ see below }

20.3.1.6 tuple concept maps

Add the following new section:

1 A tuple object of two iterators can be used with the range-based for statement due to the following concept maps:

template<InputIterator Iter> 
concept_map Range< tuple<Iter,Iter> > 
{ 
    typedef Iter iterator; 
    Iter begin( tuple<Iter,Iter>& p );
    Iter end( tuple<Iter,Iter>& p );
};

template<InputIterator Iter> 
concept_map Range< const tuple<Iter,Iter> > 
{ 
    typedef Iter iterator; 
    Iter begin( const tuple<Iter,Iter>& p );
    Iter end( const tuple<Iter,Iter>& p );
};
  • Iter begin( tuple<Iter,Iter>& p );
  • Iter begin( const tuple<Iter,Iter>& p );

2 Returns: std::get<0>(p)

  • Iter end( tuple<Iter,Iter>& p );
  • Iter end( const tuple<Iter,Iter>& p );

3 Returns: std::get<1>(p)

26.5.1 Header <valarray> synopsis

Add the following to the synopsis:

template<class T>
concept_map Range< valarray<T> >
{ see below/ }

template<class T>
concept_map Range< const valarray<T> >
{ see below }

26.5.2.7 valarray concept maps

Add the following new section:

1 valarray objects can be used with the range-based for statement due to the following concept maps.

template<class T>
concept_map Range< valarray<T> >
{
    typedef unspecified type iterator;
    iterator begin( valarray<T>& a );
    iterator end( valarray<T>& a );
};
  • typedef unspecified type iterator;

2 Requires: iterator shall meet the requirements of the MutableRandomAccessIterator concept

  • iterator begin( valarray<T>& a );

3 Returns: an iterator referencing the first value in the numeric array.

  • iterator end( valarray<T>& a );

4 Returns: an iterator one past the last value in the numeric array.

template<class T>
concept_map Range< const valarray<T> >
{ 
    typedef unspecified type iterator; 
    iterator begin( const valarray<T>& a );
    iterator end( const valarray<T>& a );
};
  • typedef unspecified type iterator;

5 Requires: iterator shall meet the requirements of the RandomAccessIterator concept but not MutableRandomAccessIterator.

  • iterator begin( const valarray<T>& a );

6 Returns: an iterator referencing the first value in the numeric array.

  • iterator end( const valarray<T>& a );

7 Returns: an iterator one past the last value in the numeric array.

28.4 Header <regex> synopsis

Add the following to the synopsis:

<BidirectionalIterator Iter> 
concept_map Range< sub_match<Iter> > 
{ see below }

template<BidirectionalIterator Iter> 
concept_map Range< const sub_match<Iter> >
{ see below }

28.9.3 sub_match concept maps

Add the following new section:

1 sub_match objects can be used with the range-based for statement due to the following concept maps:

<BidirectionalIterator Iter> 
concept_map Range< sub_match<Iter> > 
{ 
    typedef Iter iterator; 
    Iter begin( sub_match<Iter>& p );
    Iter end( sub_match<Iter>& p );
};

template<BidirectionalIterator Iter> 
concept_map Range< const sub_match<Iter> > 
{ 
    typedef Iter iterator; 
    Iter begin( const sub_match<Iter>& p );
    Iter end( const sub_match<Iter>& p );
};
  • Iter begin( sub_match<Iter>& p );
  • Iter begin( const sub_match<Iter>& p );

2 Returns: p.first

  • Iter end( sub_match<Iter>& p );
  • Iter end( const sub_match<Iter>& p );

3 Returns: p.second