Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

for_each & ranged base for on 2D array

Tags:

c++

arrays

c++11

I was trying to print a 2D array using for_each and range based for loop.

My program goes like this:-

#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 did my first for_each throw errors and why is & symbol necessary for row? What is its type? Is row a pointer?

like image 441
Anwesha Avatar asked Jun 03 '15 20:06

Anwesha


People also ask

What is std :: For_each?

std::for_each is an STL algorithm that takes a collection of elements (in the form of a begin and end iterator) and a function (or function object), and applies the function on each element of the collection. It has been there since C++98.

Which is the correct syntax of For_each () *?

Syntax: for_each (InputIterator start_iter, InputIterator last_iter, Function fnc) start_iter : The beginning position from where function operations has to be executed. last_iter : The ending position till where function has to be executed.

Is there a for each in C++?

There is no foreach loop in C, but both C++ and Java have support for foreach type of loop. In C++, it was introduced in C++ 11 and Java in JDK 1.5. 0 The keyword used for foreach loop is “for” in both C++ and Java.

What does the standard library find algorithm return?

Return value The find() function returns an iterator that points to the val in the specified range. If the value is not found, then it returns an iterator to the last of the array or vector.


1 Answers

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

begin(a) yields an int(*)[3] (pointer to array of size [3]), and dereferencing it yields an 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]) yields an int* that points to the first element in the first row of a, and end(a[2]) yields an int* pointing to one past the last element in the last row of a, so everything works.


Now for the range-based for part.

If you remove the & from the line for (auto& row : a) the error actually occurs on the following line for(auto x : row). This is because of the way the range-based for is specified. The clause pertinent to your use case is

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 has unknown size or is of an incomplete type, the program is ill-formed)

Hereon I'll be referring to the identifiers mentioned in the Explanation section of the linked page.


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

__range is deduced as int(&)[3][3] (reference to array of size [3][3]). __begin is then deduced as int(*)[3] (pointer to array of size [3]) because the type of __range decays to a pointer to the first row of the 2D array. The range_expression you have is auto& row, so row is deduced as int(&)[3] (reference to array of size [3]).

Next, the same process is repeated for the inner range-based for. In this case, __range is int(&)[3] and the array clause I quoted above applies; the remaining type deduction process is similar to what I described above.

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

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

__range, __begin and __end are all deduced the same. The crucial difference in this case is the range_expression auto row, which causes decay of the int(*)[3] type that __begin was deduced as. This means row is deduced as int *, and none of the 3 clauses where the determination of begin_expr/end_expr are described handle a raw pointer. This results in a compilation error within the nested for loop.

like image 55
Praetorian Avatar answered Sep 18 '22 02:09

Praetorian