Reputation: 42371
#include <vector>
using namespace std;
class A
{
public:
A() = default;
void Add()
{
a++;
}
private:
int a;
};
int main()
{
vector<A> x(10);
for (auto pos = x.begin(); pos != x.end(); ++pos) pos->Add();
}
for_each
seems non-modifying. http://en.cppreference.com/w/cpp/algorithm/for_each
f - function object, to be applied to the result of dereferencing every iterator in the range [first, last)
The signature of the function should be equivalent to the following:
void fun(const Type &a);
The signature does not need to have const &. The type Type must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type.
So, my question is:
Is there a standard function/way to do the same as for (auto pos = x.begin(); pos != x.end(); ++pos) pos->Add();
does?
Upvotes: 6
Views: 7806
Reputation: 114511
You could use
for(auto& p : x) p.Add();
this code simple and elegant but is also quite efficient as it allows the compiler to see directly the action without interposing extra logic. Less typing, faster compiling, no nonsense screenfuls of babbling when making typos.
For example the code generated by g++ for
for (auto& y : x) {
y++;
}
where x
is declared as an std::vector<int>
has an inner loop like
.L8:
movdqa (%rdi,%rax), %xmm0
addq $1, %rdx
paddd %xmm1, %xmm0
movaps %xmm0, (%rdi,%rax)
addq $16, %rax
cmpq %rdx, %r8
ja .L8
where 4 integers are incremented at each iteration using mmx instructions.
Upvotes: 5
Reputation: 70526
Late answer, but noone has mentioned std::transform
:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
class A
{
public:
A() = default;
A& Add()
{
a++;
return *this; // this will make it compatible with std::transform
}
friend std::ostream& operator<<(std::ostream& os, A const& a)
{
return os << a.a;
}
private:
int a;
};
int main()
{
vector<A> x(10);
std::transform(x.begin(), x.end(), x.begin(), [](auto& elem) {
return elem.Add();
});
std::copy(x.begin(), x.end(), std::ostream_iterator<A>(std::cout, ","));
}
Note that I had to modify the return type of your Add()
to A&
. This makes it compatible with std::transform
, and also mimics the return type of operator++
.
Of course, a raw-loop with a single statement, or a for_each
are fine as well. But transform
is a vocabulary algorithm that immediately signifies to readers of your code that you are modifying the container. From a raw loop and for_each
, this requires more careful scrutiny (trivial here perhaps, but in larger code these things add up). Notice e.g. the difference between
std::transform(x.begin(), x.end(), x.begin(), [](auto& elem) {
// many lines but x will always be written to
});
std::for_each(x.begin(), x.end(), [](auto& elem) {
// many lines, will always need to inspect the code here
// to know if `elem` is actually being written to
// the `auto&` is only a hint that this might happen
});
Upvotes: 3
Reputation: 76297
Not sure why you write that
for_each is non-modifying
this works just fine:
for_each(begin(x), end(x), [](int &i){++i;});
for a vector
of integers, e.g.
Upvotes: 11
Reputation: 20274
std::for_each
is acutely what are you looking for:
std::for_each(std::begin(x),std::end(x),[](A& item){item.add();});
However, 6502's answer is the better way.
Edit:
About the quote you reference. In the same page notice:
f may modify the elements of the range through the dereferenced iterator
Upvotes: 4