范围参考

时间:2014-11-21 14:01:04

标签: c++ c++11 reference

我研究过引用总是需要初始化。 那么为什么这段代码在我的C ++书中作为范围的例子报告应该是正确的呢?

#include <iostream>
#include <vector>

using namespace std;

int main ()    
{
    vector <int> v {0, 1, 2, 3}    // should double each element of v,
                                   // without writing it.
    for (auto &r : v) 
    {
       r *= 2;
    }

    return 0;
}

感谢您的所有答案,我知道您是所有熟练的程序员...... 但是有些答案对我来说仍然太先进了,所以我会为我选择最容易理解的答案。再次谢谢!

5 个答案:

答案 0 :(得分:3)

在基于语句的范围的语义描述中有书面

for-range-declaration = *__begin;

相对于您的示例,这相当于

auto &r = *__begin;

即该引用始终被初始化。

以下是来自C ++标准

的声明范围的完整语义定义
{
    auto && __range = range-init;
    for ( auto __begin = begin-expr,
          __end = end-expr;
          __begin != __end;
          ++__begin ) {
          for-range-declaration = *__begin;
          statement
    }
}

这就是这句话

for ( for-range-declaration : expression ) statement

在语义上等同于上面的结构。

例如,如果 expression 是一个名为a的数组,其中包含N个元素,那么循环将看起来像

for ( auto __begin = a, __end = a + N; __begin != __end; ++__begin ) 
{
    auto &r = *__begin;
    //...
}

答案 1 :(得分:2)

我总是想到

for (auto &r : v)
{
    ...
}

等同于

std::for_each(std::begin(v),std::end(v),[&](auto &r)
{
    ...
});

请注意,lambda中的auto &r需要C ++ 14。

编辑或混合@VladfromMoscow标准中的定义和@JBL的答案

    for(
      auto it = std::begin(v),
      end = std::end(v); 
      it != end;
      ++it)
    {
        auto& r = *it;
        //Loop code
    }

也许这比标准中的描述更容易掌握(尽管它不如标准中的描述那么精确)。

答案 2 :(得分:1)

在每次迭代中初始化引用,以引用向量的每个元素。

这种for-loop的风格大致等同于

for (auto it = v.begin(); it != v.end(); ++it) {
    auto &r = *it;
    // your code goes here
}

您可以在其中看到引用已初始化。

如果您对血腥细节感兴趣,另一个答案会引用语言标准的完整定义。

答案 3 :(得分:0)

因为基于范围的for循环的语义大致等同于以下(可读)代码:

auto it = v.begin();
for(; it != v.end(); ++it){
    auto& r = *it;
    //Loop code
}

也就是说,每次都声明并初始化它。

答案 4 :(得分:0)

auto& r组件并不代表整个声明;它只指定在每次迭代时生成的元素的类型和名称。

在每次迭代开始时,由range-for的内部处理初始化。这才是重点! :)

同样,在下文中,您不会自己为x分配值;它是由循环完成的:

for (int x : v) {}