基于范围的for循环等效写法

4
根据 n2243,基于范围的for循环等同于以下内容:
{
     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
     }    
}

它接着说:如果在使用基于范围的for语句之前未包含头文件<iterator_concept>,则程序将无法形成。 所以我怀疑这个信息是否最新。我也很好奇std::Range是什么或者它是否纯粹是一个实现细节。我能找到的最接近的是n3350
这个答案依赖于这个信息,并且说:

Range for循环尽可能快,因为它缓存了终止迭代器[citation],使用前置递增并且只引用一次迭代器。

所以如果你经常写:

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

那么,是的,range-for可能会稍微快一点,因为它更容易编写,没有理由不使用它(在适当的情况下)。

P.S. 我说它尽可能快,但它并不比可能更快。如果你仔细编写手动循环,可以实现完全相同的性能。

我很好奇它现在是否真的有所不同。就我所看到的,它只是一种语法糖。例如,在一个循环中,你可以这样做:auto it = s.rbegin(); it != s.rend(); ++it,但它需要返回反向迭代器的样板代码,而范围-based 的循环则期望 beginend。如果它只是为了节省打字,那么它还有什么其他优点呢?因为它期望 beginend。我很好奇上面引用的答案是否仍然有权威性,因为该论文出自2007年。

这个提案(N2243)相当古老(这是关于这个主题的第二个提案吗?),已经被多次修订。我能找到的最新的个人论文是N2930,仍然存在一个在N3257中讨论的缺陷。考虑使用N3337或标准本身作为现在定义的来源。std::Range部分已被替换。 - dyp
1个回答

3

正如@DyP所说,这个部分在最终标准中有了一些变化。C++11 6.5.4范围for语句[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.


这也引发了一个问题,即是否已经有一些标准草案的源代码,格式为SO兼容的Markdown / HTML(可能是从latex源代码派生而来?;)) - dyp
@DyP 那将是不可思议的,我们应该开始一个实现翻译器的项目。 - Casey
我想撤回关于引用块的评论。它并没有真正提高可读性。至于Markdown:快速谷歌搜索显示出Pandoc,我会尝试一下(它也在GPL下)。 - dyp
@DyP 我认为不用白色和灰色分开会更好一些。 - Casey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接