Enhanced FOR loops in C++
I am switching from Java to C++ and I was wondering whether C++ contains the enhanced for loops that I used in java, in example:
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
for (int item : numbers) {
System.out.println("Count is: " + item);
}
Is this same "shortcut" possible in C++?
C++11 does. They are called range-based fors. Remember that you should qualify the type as a reference or a reference to const.
The workaround for C++03 is BOOST_FOR_EACH or boost::bind in combination with std::for_each. More fancy things are possible with Boost.Lambda. Should you be in the mood to frustrate either yourself or your co-workers I recommend the deprecated binders std::bind1st
and std::bind2nd
.
Here is some example code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/lambda/lambda.hpp>
#include <functional>
int main()
{
int i = 0;
std::vector<int> v;
std::generate_n(std::back_inserter(v), 10, [&]() {return i++;});
// range-based for
// keep it simple
for(auto a : v)
std::cout << a << " ";
std::cout << std::endl;
// lambda
// i don't like loops
std::for_each(v.begin(), v.end(), [](int x) {
std::cout << x << " ";
});
std::cout << std::endl;
// hardcore
// i know my lib
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// boost lambda
// this is what google came up with
// using for the placeholder, otherwise this looks weird
using namespace boost::lambda;
std::for_each(v.begin(), v.end(), std::cout << _1 << " ");
std::cout << std::endl;
// fold
// i want to be a haskell programmer
std::accumulate(v.begin(), v.end(), std::ref(std::cout),
[](std::ostream& o, int i) -> std::ostream& { return o << i << " "; });
return 0;
}
In C++11, if your compiler supports it, yes it is. It's called range-based for.
std::vector<int> v;
// fill vector
for (const int& i : v) { std::cout << i << "\n"; }
It works for C style arrays and any type that has functions begin()
and end()
that return iterators. Example:
class test {
int* array;
size_t size;
public:
test(size_t n) : array(new int[n]), size(n)
{
for (int i = 0; i < n; i++) { array[i] = i; }
}
~test() { delete [] array; }
int* begin() { return array; }
int* end() { return array + size; }
};
int main()
{
test T(10);
for (auto& i : T) {
std::cout << i; // prints 0123456789
}
}
There is no such a possibility in C++03. However new standard (C++11) does have it. See example (taken from Wikipedia):
int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array) {
x *= 2;
}
Consider also using std::vector<int>
instead of an ordinary array. This is C++ analogy for C data types, which makes life easier.
Yes and no.
1. Local array: No, but you can easily find the size
If you have a local array (int numbers[4] = {1, 2, 3, 4];
) then you can do size = sizeof(numbers) / sizeof(int)
.
2. Pointer to array: Not at all, you have to pass the size around separately
If you have a pointer to an array (int* numbers = new int[4];
) then you can't figure out the size unless you keep track of it yourself. (or if it's null terminated in the case of a c string, but then you have to iterate through it which is linear running time...)
Note that I don't believe pointer to array is the proper terminology, really you just have a pointer to the first element of the array but space for multiple values has been allocated. Not sure what this is called. Maybe just a pointer?
3. STL containers: Yes, and you can do some for loop magic using iterators, or just use indices by getting the size
If you have a vector (std::vector<int> v(3, 0);
) then you can iterate through it the following ways:
C++11:
auto it = v.begin();
for (auto it = v.begin(); it != v.end(); it++)
{
UseElement(*it);
}
Or apparently (also C++11, thanks jrok):
for (const int& i : v) { UseElement(i); }
C++ (pre-11):
std::vector<int>::iterator it;
for (it = v.begin(); it != v.end(); it++)
{
UseElement(*it);
}
Or using indices:
for (int i = 0; i < v.size(); i++)
{
UseElement(v[i]);
}
Furthermore, you can use function pointers or functors with STL containers using std algorithm's for_each (#include <algorithm>
) like so:
void foo(int i)
{
std::cout << i;
}
{
std::for_each(myvector.begin(), myvector.end(), foo);
}