我尝试使用for_each
和基于范围的for
循环打印2D数组。
我的程序是这样的: -
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
//for_each (begin(a), end(a), [] (int x) { cout<<x<<" ";}); this code throws error
for_each (begin(a[0]), end(a[2]), [] (int x) { cout<<x<<" ";}); //this code works well, why ?
cout<<endl;
for (auto &row: a) // without & for row, error is thrown
{
for (auto x:row) // no & needed for x, why ?
{
cout<<x<<" ";
}
}
return 0;
}
为什么我的第一个for_each
抛出错误以及为什么行需要&
符号?它的类型是什么? row
是指针吗?
答案 0 :(得分:4)
for_each (begin(a), end(a), [] (int x) { cout<<x<<" ";});
begin(a)
产生一个int(*)[3]
(指向大小为[3]的数组的指针),并且取消引用它会产生int(&)[3]
,而你的lambda表达式需要一个int
参数。
for_each (begin(a[0]), end(a[2]), [] (int x) { cout<<x<<" ";});
begin(a[0])
会产生一个int*
,指向a
第一行中的第一个元素,而end(a[2])
会产生int*
指向一个过去的a
<{1}}的最后一行中的最后一个元素,所以一切正常。
现在是基于范围的for
部分。
如果从&
行中删除for (auto& row : a)
,则错误实际发生在以下行for(auto x : row)
上。这是因为指定了range-based for
的方式。与您的用例相关的条款是
如果
__range
是一个数组,那么 begin_expr 是__range
而 end_expr 是(__range + __bound)
,其中__bound
是数组中元素的数量(如果数组大小未知或类型不完整,则程序格式错误)
在此,我将引用链接页面的解释部分中提到的标识符。
考虑案例for (auto& row : a)
:
__range
推导为int(&)[3][3]
(对大小数组的引用[3] [3])。然后将__begin
推导为int(*)[3]
(指向大小数组的指针[3]),因为__range
的类型衰减到指向2D数组的第一行的指针。您拥有的 range_expression 为auto& row
,因此row
推导为int(&)[3]
(对大小数组的引用[3])。
接下来,对基于内部范围的for
重复相同的过程。在这种情况下,__range
为int(&)[3]
,并且上面引用的数组子句适用;剩下的类型扣除过程与我上面描述的类似。
__range = int(&)[3]
__begin = int*
x = int
现在考虑案例for (auto row : a)
:
__range
,__begin
和__end
都是相同的。在这种情况下,最重要的区别是 range_expression auto row
,这会导致推断出int(*)[3]
__begin
类型的衰减。这意味着row
被推断为int *
,并且描述 begin_expr / end_expr 的确定的3个子句中没有一个处理原始指针。这会在嵌套的for
循环中导致编译错误。
答案 1 :(得分:3)
a
是一个二维数组 - 如果您愿意,可以int[][]
。
这意味着当您迭代a
时,您只迭代第一个数组维度 - a[0]
到a[2]
。 a[0]
仍然是一个数组,它解释了为什么您的第一个for_each
可能会产生错误 - 您提供的lambda期望int
,但会传递int*
。
出于同样的原因,在第一个基于范围的基础中需要参考(&amp;符号)。没有&amp;编译器尝试按值复制第一维中的项,但这些是数组本身,并且您无法在C ++中按值复制数组。
第二个基于范围的for不需要引用,因为它正在迭代第二个数组维,它由简单的整数组成。