Reputation: 1965
I know I can have any type in for loop to iterate over:
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
int ar[] ={ 1, 2, 3 };
for (int i:ar)
{
cout << i << endl;
}
}
But I could not have an pointer type:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
for (char *p:argv) //or better char const *p
// using auto keyword expands to error-type in vscode
{
ifstream in(p);
}
return 0;
}
will give:
error: ‘begin’ was not declared in this scope
for (char *p:argv)
error: ‘end’ was not declared in this scope
for (char *p:argv)
^~~~
So I am assuming, the syntax of c++ for loop (auto var : vector/array)
is not the same as c
-style, old-fashion loop for(int i=0; i<size; i++)
? Because I am required (in case of using c++ style for loop) to provided a structure with valid iterator (thus the errors, looking for begin() and end() iterators. But then why did the first case works? The first case, an array with ints, is also a structure without any kind of iterators, but old pointers (to access). So why the first is okay, but the second isn't?
Upvotes: 0
Views: 866
Reputation: 508
The difference in those samples is hidden inside the rules of passing parameters to functions.
In the first example, when you write int ar[] = {1, 2, 3};
, the type of ar
is int[3]
- "an array of 3 ints". std::begin
is defined for arrays, so the code compiles and works.
In the second example, char const *argv[]
is actually the same as char const **argv
, because in function parameters, you cannot pass an array by value, and the syntax []
is compiled exactly as if you would have used *
. Obviously, there is no std::begin
for pointers, so the code does not work.
To iterate over the arguments, you would have to use an ordinary for loop. For example,
for (int i = 0; i < argc; ++i) {
char const* arg = argv[i];
};
Edit: Just to clarify - to use a range-based for loop, std::begin(a)
and std::end(a)
should be callable and return an iterator. (not entirely true since C++17 - std::end
could return anything that is comparable with the iterator, this is called a sentinel in the C++20 working draft)
In case of an array with known bound (such as int[3]
), std::begin
returns a pointer to the first element, and std::end
returns a pointer past-the-end. An iterator
in C++ does not have to be a derived class of some special base, it just has to have the right semantics. Pointers are also iterators.
Upvotes: 1