The legacy std::for_each
returns function as the standard only requires Function
to meet Cpp17MoveConstructible according to [alg.foreach]:
template<class InputIterator, class Function> constexpr Function for_each(InputIterator first, InputIterator last, Function f);
Preconditions:
Function
meets the Cpp17MoveConstructible requirements.[Note:
Function
need not meet the requirements of Cpp17CopyConstructible. end note]
This is reasonable since the user may want to reuse the function after the call.
The parallel version of for_each
has no return:
template<class ExecutionPolicy, class ForwardIterator, class Function> void for_each(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Function f);
Preconditions:
Function
meets the Cpp17CopyConstructible requirements.
This is because the standard requires Function
to meet the Cpp17CopyConstructible, so returning the function is unnecessary as the user can freely create a copy if they want on the call side.
I noticed that ranges::for_each
also returns the function:
template<input_iterator I, sentinel_for<I> S, class Proj = identity, indirectly_unary_invocable<projected<I, Proj>> Fun> constexpr ranges::for_each_result<I, Fun> ranges::for_each(I first, S last, Fun f, Proj proj = {});
However, the function signature already requires Fun
to satisfy indirectly_unary_invocable
which already guarantees that it is copy constructible.
The question is, why does the ranges::for_each
still return the function? What's the point of doing this?
It returns the functor because that allowed some clever tricks with stateful functors back in the day (in C++98, I assume). You don't see those often today, because lambdas are usually more straightforward.
Here's an example:
#include <algorithm>
#include <iostream>
struct EvenCounter
{
int count;
EvenCounter() : count(0) {}
void operator()(int x)
{
if (x % 2 == 0)
count++;
}
};
int main()
{
int array[] = {1,2,3,4,5};
int num_even = std::for_each(array, array+5, EvenCounter()).count;
std::cout << num_even << '\n';
}
This is reasonable since the user may want to reuse the function after the call.
I think the logic is backwards here. The function isn't required to be copyable simply because there's no reason for for_each
to copy it.
If you have a non-copyable (or even non-movable) function, you can pass it by reference using std::ref
to avoid copies/moves, so you don't win anything here from the algorithm returning the function back to you.
There was no std::ref
in C++98, but there was also no move semantics, so for_each
couldn't have worked with non-copyable functors in the first place.