循环访问二维数组时出现如下问题:
error: invalid range expression of type 'int *'; no viable 'begin' function available
for (auto col : row){
^ ~~~
1 error generated.
问题复现
初始化数组
constexpr size_t rowCnt = 3, colCnt = 4;
int ia[rowCnt][colCnt];
for (size_t i = 0; i != rwoCnt; i++){
for (size_t j = 0; j != colCnt; j++){
ia[i][j] = i * colCnt + j;
}
}
C++11中新增了范围for语句,所以前一程序可以简化成如下形式
size_t cnt = 0;
for (auto &row : ia){
for (auto &col : row){
col = cnt;
cnt++;
}
}
这个循环赋给ia元素的值和之前那个循环是完全相同的,区别之处是通过使用范围 for语句把管理数组索引的任务交给了系统来完成。
因为要改变元素的值,所以得把控制变量 row和col声明成引用类型。
第一个for循环遍历ia的所有元素,这些元素是大小为 4 的数组,因此 row的类型就应该是含有4个整数的数组的引用。
第二个 for 循环遍历那些4元素数组中的某一个,因此col的类型是整数的引用。每次迭代把 cnt 的值赋给 ia 的当前元素,然后将 cnt 加 1。
在上面的例子中,因为要改变数组元素的值,所以我们选用引用类型作为循环控制变量,但其实还有一个深层次的原因促使我们这么做。举一个例子,考虑如下的循环∶
for (const auto &row : ia){
for (auto col : row){
cout << col << endl;
}
}
这个循环中并没有任何写操作,可是我们还是将外层循环的控制变量声明成了引用类型,这是为了避免数组被自动转成指针。假设不用引用类型,则循环如下述形式∶
for (auto row : ia){
for (auto col : row){
cout << col << endl;
}
}
程序将无法通过编译。这是因为,像之前一样第一个循环遍历 ia的所有元素,注意这些元素实际上是大小为 4的数组。编译器会有如下提示,
因为 row不是引用类型,所以编译器初始化row 时会自动将这些数组形式的元素(和其他类型的数组一样)转换成指向该数组内首元素的指针。这样得到的 row 的类型就是 int * ,显然内层的循环就不合法了,编译器将试图在一个 int * 内遍历,这显然和程序的初衷相去甚远。
因为 row不是引用类型,所以编译器初始化row 时会自动将这些数组形式的元素(和其他类型的数组一样)转换成指向该数组内首元素的指针。这样得到的 row 的类型就是 int * ,显然内层的循环就不合法了,编译器将试图在一个 int * 内遍历,这显然和程序的初衷相去甚远。
参考
https://www.cnblogs.com/lihello/p/14314018.html