在范围内引用

Reference in range for

本文关键字:引用 范围内      更新时间:2023-10-16

我研究了引用总是需要初始化的。那么,为什么在我的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;
}

谢谢你们所有的回答,我知道你们都是熟练的程序员......但是有些答案对我来说还是太高级了,所以我会选择最适合我的。再次感谢!

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

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

在语义上等效于上面的构造。

例如,如果表达式是一个名为 a 的数组,其中包含 N 个元素,则循环将如下所示

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

我总是喜欢想到

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
    }

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

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

这种风格的 for 循环大致相当于类似的

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

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

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

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

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

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

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

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

同样,在下文中,您不会自行为x赋值;它由循环完成:

for (int x : v) {}