'Use of a functor on for_each
Why does the for_each
call on functor doesn't update sum::total
at the end?
struct sum
{
sum():total(0){};
int total;
void operator()(int element)
{
total+=element;
}
};
int main()
{
sum s;
int arr[] = {0, 1, 2, 3, 4, 5};
std::for_each(arr, arr+6, s);
cout << s.total << endl; // prints total = 0;
}
Solution 1:[1]
for_each
takes the functor by value - so it is copied. You can e.g. use a functor which is initialized with a pointer to an external int.
struct sum
{
sum(int * t):total(t){};
int * total;
void operator()(int element)
{
*total+=element;
}
};
int main()
{
int total = 0;
sum s(&total);
int arr[] = {0, 1, 2, 3, 4, 5};
std::for_each(arr, arr+6, s);
cout << total << endl; // prints total = 15;
}
Or you can use the return value from for_each
struct sum
{
sum():total(0){};
int total;
void operator()(int element)
{
total+=element;
}
};
int main()
{
sum s;
int arr[] = {0, 1, 2, 3, 4, 5};
s = std::for_each(arr, arr+6, s);
cout << s.total << endl; // prints total = 15;
}
Solution 2:[2]
for_each
receives a copy of your functor by value. Even after that, it's free to copy it, but does return a copy.
OTOH, you're simply trying to re-invent std::accumulate
, which will do the job much more easily:
int total = std::accumulate(arr, arr+6, 0);
cout << total << endl;
Solution 3:[3]
Because the s
which you pass to the for_each
is by value. for_each
accepts it by value!
In C++0x, you can solve this problem with for_each
as,
int sum = 0;
std::for_each(arr, arr+6, [&](int n){ sum += n; });
std::cout << sum ;
Output:
15
Demo at ideone : http://ideone.com/s7OOn
Or you can simple write in the std::cout
itself:
std::cout<<std::for_each(arr,arr+6,[&](int n)->int{sum += n;return sum;})(0);
Run : http://ideone.com/7Hyla
Note such different syntax is okay for learning purpose, as to how std::for_each
works, and what it returns, but I would not recommend this syntax in real code. :-)
In C++, you can write user-defined conversion function in the functor as,
struct add
{
int total;
add():total(0){};
void operator()(int element) { total+=element; }
operator int() { return total ; }
};
int main()
{
int arr[] = {0, 1, 2, 3, 4, 5};
int sum = std::for_each(arr, arr+6, add());
std::cout << sum;
}
It's slightly different version from Erik second solution : http://ideone.com/vKnmA
Solution 4:[4]
This happens due to std::for_each requires the functor to be passed by value . A workaround for your solution:
struct sum
{
sum():total(0){};
int total;
sum(sum & temp)
{
total = temp.total;
}
void operator()(int element)
{
total+=element;
}
};
int main()
{
sum s;
int arr[] = {0, 1, 2, 3, 4, 5};
s = std::for_each(arr, arr+6, s); // result of for_each assigned back to s
cout << s.total << endl; // prints total = 0;
}
Solution 5:[5]
std::ref()
is also another option if you want your object state gets updated after std::for_each
struct Sum
{
int total = 0;
void operator()(int i) { total += i; }
};
int main()
{
int arr[] = { 0, 1, 2, 3, 4, 5 };
Sum obj1;
Sum t1 = std::for_each(arr, arr + 6, obj1); // t1.total = 15
// (Note: obj1.total = 0 bcos it is passed by value)
Sum obj2;
std::for_each(arr, arr + 6, std::ref(obj2)); // obj2.total = 15 (NO copy)
Sum t2 = std::for_each(arr, arr + 6, Sum()); // t2.total = 15
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Erik |
Solution 2 | Jerry Coffin |
Solution 3 | |
Solution 4 | rahul |
Solution 5 | SridharKritha |