为什么自动在 "range for" 中的 2D 和 1D 数组中的工作方式不同 C++



嗨,我正在使用 2D 和 1D 数组C++并使用范围来访问元素。我使用的代码如下:

对于 2D 阵列

int ia[3][4] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
for (auto& row : ia) {
for (auto col : row) {
cout << col << endl;
}
}

对于 ID 数组

int base_array[2] = { 1, 2 };
for (auto p : base_array) {
std::cout << p << std::endl;
}

因此,正如我们在 2D 数组的外部循环范围中看到的那样,控制变量必须是引用类型,这样就不会发生自动数组到指针的转换,我们可以循环访问本身是大小为 4 的数组的元素。但是在 1D 数组中,我们不使用控制变量p作为参考类型,即使这样,我们也能够遍历 1D 数组。我的问题是为什么在一维数组中没有发生数组到指针的转换?如果没有引用类型的控制变量,它是如何工作的?也就是说,为什么(如何)pint类型而不是在一维数组情况下int*,而如果我们省略控制变量中的参考符号,它将变成 int*,但是当我们在变量前面包含参考符号时,它将变成数组类型。为什么会有这种行为差异?

在您的 1D 情况下,base_array 不会衰减,因为它与 for 循环存在于同一范围内。因此,基于范围的 for 可以正确计算出其范围。真的是这样,1D没有衰减。如果您尝试通过函数传递该 1D 数组,您会发现基于范围的 for 变得不可能,因为它会衰减,除非您将其作为引用传递。

在你的2D情况下,如果你允许row衰减到int*,嵌套的for不能再假设你必须意味着一个数组。因此,您可以使用auto&来保留类型,允许嵌套的 for 知道您在说什么。

为什么在一维数组中没有发生数组到指针的转换?

在1D数组的情况下,数组的元素是int对象,而在2D数组的情况下,数组的元素是"int"对象的数组。

如果不使用引用,int数组将衰减到指针。因此,对第一种情况使用参考是合适的。

情况1(行前面没有参考符号)

对于外部循环,循环变量row初始化为ia的第一个元素,该元素本身就是一个数组,因此将进行数组到指针的转换,并且row将变得int*。由于我们无法循环int*,当我们尝试在内部 for 循环中这样做时,我们会得到一个错误。

情况2(行前面有参考符号)

当我们在row的字体中添加引用符号时,该数组到指针的转换将不再发生,row将是数组类型而不是指针类型,并且由于我们可以循环遍历数组,因此这种情况将起作用。

来自 C++ 17 标准(10.1.7.4.1 占位符类型扣除)

4 如果占位符是自动类型说明符,则推导的类型 T0 替换 T 是使用模板参数的规则确定的 演绎。通过将 auto 的出现次数替换为 要么是新发明的类型模板参数 U,要么是 初始化是复制列表初始化,使用 标准::initializer_list。使用模板参数的规则推导出 U 的值 从函数调用中扣除 (17.8.2.1)

和(17.8.2.1 从函数调用中推导模板参数)

2 如果 P 不是引用类型:

(2.1) — 如果 A 是数组类型,则由 数组到指针的标准转换 (7.2) 用于代替 A 表示 类型扣除;否则

因此,如果您不会在循环中使用引用的类型

for (auto row : ia)

然后变量行的类型将被int *也就是说,它将是一个指针类型,你不能使用基于范围的 for 循环。

最新更新