以下两段代码之间的唯一区别是引用的使用。我理解为什么第一个代码片段无法编译,并且正在寻求帮助以理解为什么第二个代码编译。
第一个片段:
int a[2][3] = {0,1,2,3,4,5};
for (auto row : a)
for (auto column : row)
cout << column << endl;
以上代码无法编译,因为&#39;行&#39;是指向int的指针,它不是序列。
第二个片段:
int a[2][3] = {0,1,2,3,4,5};
for (auto &row : a)
for (auto column : row)
cout << column << endl;
此代码编译。如果我正确理解了汽车是如何工作的,那就排好&#39;是指向int的指针。但为什么这个引用可以被视为一个序列而不是常规指针?
答案 0 :(得分:5)
通过模板参数推导来完成类型的推导。
template <typename U>
void foo(U&); // Equivalent to auto&
foo(row);
这总是会将U
推断为row
的确切类型(如果它是本例中的左值),它会为我们提供数组我们想要的类型。
仅对非参考参数执行的是数组到指针的衰减。
答案 1 :(得分:4)
外部迭代的每个元素都是一个数组。在第一种情况下,auto
采用元素值,所以数组指针发生衰减,然后你就不能遍历单个指针。
在第二种情况下,您将获得对数组的引用,您当然可以迭代它。
答案 2 :(得分:0)
std::begin
和std::end
没有指针类型的重载。基于范围的for循环被定义为使用这些函数。如果要防止发生数组到指针的转换,可以绑定对数组的引用。
§8.5.3
5
对“ cv1T1
”类型的引用由表达式初始化 类型“ cv2T2
”如下:- 如果引用是左值引用和初始化器 表达
- 是左值(但不是位字段),“ cv1
T1
”是 参考兼容“ cv2T2
,”或- 有类类型(即
T2
是类类型),其中T1
不是 与T2
相关的引用,可以隐式转换为 类型为“ cv3T3
的左值”,其中“ cv1T1
”是 参考兼容“ cv3T3
” 106 (此转换 通过枚举适用的转换函数来选择 (13.3.1.6)并通过重载分辨率选择最佳的一个 (13.3)),然后将引用绑定到初始化表达式lvalue中 第一种情况和转化的左值结果 第二种情况(或者,在任何一种情况下,到适当的基类 对象的子对象)。 [注意:通常的左值到右值(4.1), 数组到指针(4.2)和函数到指针(4.3)标准 不需要转换,因此在这样的情况下会被抑制 直接绑定到左值。 - 结束记录]
由于第二个项目符号点不适用,因此引用将直接绑定到数组,并且不会发生转换。