For_each & ranged base for a 2D array

I tried to print a 2D array using a for_each loop and a range based on for .

My program is as follows: -

 #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; } 

Why are my first for_each throw errors and why is the & character needed for a string? What is its type? Is row pointer?

+6
source share
2 answers
 for_each (begin(a), end(a), [] (int x) { cout<<x<<" ";}); 

begin(a) gives int(*)[3] (a pointer to an array of size [3]), and dereferencing it gives int(&)[3] , while your lambda expression expects an int argument.

 for_each (begin(a[0]), end(a[2]), [] (int x) { cout<<x<<" ";}); 

begin(a[0]) gives an int* that points to the first element in the first line of a , and end(a[2]) gives an int* that points to one past of the last element in the last line of a , so everything works.


Now for the range-based for part.

If you remove & from the for (auto& row : a) , the error actually occurs in the next for(auto x : row) . This is due to the way the for range is specified. The section relevant to your use case,

If __range is an array, then begin_expr is __range and end_expr is (__range + __bound) , where __bound is the number of elements in the array (if the array is of unknown size or has an incomplete type, the program is poorly formed)

Here I will refer to the identifiers mentioned in the Explanation section on the linked page.


Consider the case of for (auto& row : a) :

__range is output as int(&)[3][3] (reference to an array of size [3] [3]). __begin then output as int(*)[3] (a pointer to an array of size [3]), because the __range type decays to a pointer to the first line of the 2D array. The range_expression expression has auto& row , so row is displayed as int(&)[3] (reference to an array of size [3]).

Further, the same process is repeated for the inner for range. In this case, __range is int(&)[3] , and the kernel suggestion given above applies; the residual type inference process is similar to that described above.

 __range = int(&)[3] __begin = int* x = int 

Now consider the case of for (auto row : a) :

__range , __begin and __end all output the same way. The most important difference in this case is the expression range_expression auto row , which causes the decay of type int(*)[3] , which was calculated by __begin as. This means that row is output as int * , and none of the three sentences that describe the definition of begin_expr / end_expr processes the raw pointer. This results in a compilation error inside the nested for loop.

+4
source

a is a two-dimensional array - int[][] , if you want.

This means that when you repeat iteration a you iterate only the first dimension of the array - a[0] to a[2] . a[0] is still an array that explains why your first for_each might cause an error. The lambda you provided expects an int , but int* will be passed.

A reference (& symbol) is required in the first range for the same reason. Without this, the compiler also tries to copy by value elements in the first dimension, but these are arrays themselves, and you cannot copy an array by value in C ++.

The second range, based on the base, does not need a reference because it iterates over the second dimension of an array consisting of simple ints.

+3
source

Source: https://habr.com/ru/post/988478/


All Articles