What is the difference between std::transform and std::for_each?

bendervader picture bendervader · Jun 26, 2015 · Viewed 50.9k times · Source

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?

Answer

Ilio Catallo picture Ilio Catallo · Jun 26, 2015

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::strings in a container of std::size_ts.

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;
}