I'm taking a self-study course for C++, learning how the Standard Library works, and I want to understand how this code that uses for_each
works, particularly regarding mutating objects (as opposed to native data types). I realize that you shouldn't use for_each
this way, but this is for the purpose of learning.
I had thought this code would mutate all the elements in the set, but it doesn't.
My question is: 1. Why doesn't this code mutate the set?
2. How can the code be altered so that it will modify the set? To clarify: is there a way to keep the for_each
and have it manipulate the set, or is this not possible and some other method (such as transform
) has to be used?
Code
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
class A {
int a;
public:
A(int a) : a(a) {}
int getA() const { return a; }
void setA(int a) { this->a = a; }
bool operator<(const A & b) const { return a<b.a; }
};
struct myprinter {
void operator()(const A & a) { cout << a.getA() << ", "; }
};
struct doubler {
void operator()(A a) { a.setA(a.getA()*2); }
};
int main() {
int mynumbers[] = {8, 9, 7, 6, 4, 1};
set<A> s1(mynumbers, mynumbers+6);
for_each(s1.begin(), s1.end(), doubler()); //<-- Line in question
for_each(s1.begin(), s1.end(), myprinter());
return 0;
}
//Expected output: 2, 8, 12, 14, 16, 18
//Actual output: 1, 4, 6, 7, 8, 9,
What I've tried so far
At first I thought the problem was that doubler was taking the parameter by value and not by reference, so it wasn't saving the changes to the set. But when I change the signature to be
void operator()(A & a)
, I get the error of:error: no match for call to '(doubler) (const A&) ' __f(*__first); ~~~^~~~~~~~~~ error: binding 'const A' to reference of type 'A&' discards qualifiers
I deducted that that line being pointed out is from the internal implementation of
for_each
. I cannot make the parameter a const ref, because I am trying to change thea
value using thesetA()
method, so it cannot beconst
.- If I change the set to be a vector instead, then when I changed the signature of doubler to take a reference, it successfully doubled the elements in the container. Why would it not work if the container is a set instead?
Edit: moooeeeep linked to another question that shows how to edit each element of a set. This is a practical solution to my problem, but my question is more theoretical - why can you not edit sets using for_each
, where you can edit vectors and other stl containers?