我研究过引用总是需要初始化。 那么为什么这段代码在我的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;
}
感谢您的所有答案,我知道您是所有熟练的程序员...... 但是有些答案对我来说仍然太先进了,所以我会为我选择最容易理解的答案。再次谢谢!
答案 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) {}