That for loop is called a range-based for loop. The compiler is transforming that code into something else. You can see all the details here https://en.cppreference.com/w/cpp/language/range-for (it's different for C++11, C++17, and C++20).
However, in principle, your code becomes this:
{
auto && __range = arr;
auto __begin = begin_expr;
auto __end = end_expr;
for ( ; __begin != __end; ++__begin) {
x = *__begin;
cout << x << endl;
}
}
The thing here is that begin_expr
and end_expr
can be different things. If arr
was an array, like int arr[3]
, __range
would be __range + 3
. If arr
was a class with members begin()
and end()
it would be __range.begin()
. Otherwise, it would be begin(__range)
.
This last case is were your code is landing, because arr
is not an array but a pointer to int
(int [] arr
means int* arr
). And there is no begin()
and end()
for int*
.
It works here, because in this example, arr
is an array of 4 integers:
int arr[] = { 10, 20, 30, 40 };
for (int x : arr)
cout << x << endl;
There are different ways to do this. This is how I'd prefer to do it myself:
template <typename T>
void display(std::vector<T> const & arr)
{
for (int x : arr)
cout << x << endl;
}
int main()
{
std::vector<int> arr { 10, 20, 30, 40 };
display(arr);
}
You can check https://cppinsights.io/ to see how the compiler transforms your code (to some degree). For instance, your code becomes this (mind that it does not work if the code does not compile, so I had to comment out the loop):
#include <iostream>
using namespace std;
void display(int * arr) // <-- notice int*
{
}
int main()
{
int arr[4] = {10, 20, 30, 40}; // <-- notice int[4]
display(arr);
}
And if you take this code:
int main()
{
int arr[] = { 10, 20, 30, 40 };
for (int x : arr)
cout << x << endl;
}
the result is this:
int main()
{
int arr[4] = {10, 20, 30, 40};
{
int (&__range1)[4] = arr;
int * __begin1 = __range1;
int * __end1 = __range1 + 4L;
for(; __begin1 != __end1; ++__begin1)
{
int x = *__begin1;
std::cout.operator<<(x).operator<<(std::endl);
}
}
}