Both can be used to apply a function to a range of elements.
On a high level:
std::for_each
ignores the return value of the function, and guarantees order of execution.std::transform
assigns the return value to the iterator, and does not guarantee the order of execution.When do you prefer using the one versus the other? Are there any subtle caveats?
std::transformApplies an operation sequentially to the elements of one (1) or two (2) ranges and stores the result in the range that begins at result . (1) unary operation. Applies op to each of the elements in the range [first1,last1) and stores the value returned by each operation in the range that begins at result ...
I timed the difference between both implementations using google benchmark and came to the conclusion that the loop is about 5 times faster than using std::transform.
std::transform
is the same as map
. The idea is to apply a function to each element in between the two iterators and obtain a different container composed of elements resulting from the application of such a function. You may want to use it for, e.g., projecting an object's data member into a new container. In the following, std::transform
is used to transform a container of std::string
s in a container of std::size_t
s.
std::vector<std::string> names = {"hi", "test", "foo"}; std::vector<std::size_t> name_sizes; std::transform(names.begin(), names.end(), std::back_inserter(name_sizes), [](const std::string& name) { return name.size();});
On the other hand, you execute std::for_each
for the sole side effects. In other words, std::for_each
closely resembles a plain range-based for
loop.
Back to the string example:
std::for_each(name_sizes.begin(), name_sizes.end(), [](std::size_t name_size) { std::cout << name_size << std::endl; });
Indeed, starting from C++11 the same can be achieved with a terser notation using range-based for
loops:
for (std::size_t name_size: name_sizes) { std::cout << name_size << std::endl; }
Your high level overview
std::for_each
ignores the return value of the function and guarantees order of execution.std::transform
assigns the return value to the iterator, and does not guarantee the order of execution.
pretty much covers it.
Another way of looking at it (to prefer one over the other);
One more thing to bear in mind (subtle caveat) is the change in the requirements of the operations of std::transform
before and after C++11 (from en.cppreference.com);
Basically these were to allow the undetermined order of execution.
When do I use one over the other?
If I want to manipulate each element in a range, then I use for_each
. If I have to calculate something from each element, then I would use transform
. When using the for_each
and transform
, I normally pair them with a lambda.
That said, I find my current usage of the traditional for_each
being diminished somewhat since the advent of the range based for
loops and lambdas in C++11 (for (element : range)
). I find its syntax and implementation very natural (but your mileage here will vary) and a more intuitive fit for some use cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With