user1508519
user1508519

Reputation:

Range-based for loop equivalent

So according to n2243 the range-based for loop is equivalent to this:

{
     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
     }    
}

It then says 2 If the header <iterator_concept> is not included prior to a use of the range-based for statement, the program is ill-formed. so I question how up to date this is. I'm also curious what std::Range is or if it's purely an implementation detail. The closest I can find is n3350.

This answer relies on this information and says:

Range for is as fast as possible since it caches the end iterator[citation], uses pre-increment and only dereferences the iterator once.

so if you tend to write:

for(iterator i = cont.begin(); i != cont.end(); i++) { /**/ }

Then, yes, range-for may be slightly faster, since it's also easier to write there's no reason not to use it (when appropriate).

P.S. I said it's as fast as possible, it isn't however faster than possible. You can achieve the exact same performance if you write your manual loops carefully.

I'm curious if it actually makes a difference now. As far as I can see it's just syntactic sugar. For example, in a loop where you could do auto it = s.rbegin(); it != s.rend(); ++it, it would require boiler plate code that returns reverse iterators where the ranged-based for loop expects begin and end. And if all it saves is typing, then what other advantages does it offer, since it only expects begin and end? I'm curious if the answer I quoted above still holds weight since the paper is from 2007.

Upvotes: 4

Views: 2105

Answers (1)

Casey
Casey

Reputation: 42554

As @DyP says, this section has changed a bit in the final standard. C++11 6.5.4 The range-based for statement [stmt.ranged]:

1 For a range-based for statement of the form

  for ( for-range-declaration : expression ) statement

let range-init be equivalent to the expression surrounded by parentheses

  ( expression )

and for a range-based for statement of the form

  for ( for-range-declaration : braced-init-list ) statement

let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to

  {
    auto && __range = range-init;
    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, and _RangeT is the type of the expression, and begin-expr and end-expr are determined as follows:

  • if _RangeT is an array type, begin-expr and end-expr are __range and __range + __bound, respectively, where __bound is the array bound. If _RangeT is an array of unknown size or an array of incomplete type, the program is ill-formed;

  • if _RangeT is a class type, the unqualified-ids begin and end are looked up in the scope of class _RangeT as if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration, begin-expr and end-expr are __range.begin() and __range.end(), respectively;

  • otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespace std is an associated namespace.

[ Example:

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

—end example ]

2 In the decl-specifier-seq of a for-range-declaration, each decl-specifier shall be either a type-specifier or constexpr.

Upvotes: 3

Related Questions