Daily bit(e) C++. std::transform
Daily bit(e) C++ 115, алгоритм «копирования с преобразованием» – std::transform.

Алгоритм std::transform позволяет копировать элементы из одного диапазона в другой, применяя к каждому элементу определенное преобразование. Это преобразование может изменять тип элементов результирующего диапазона.
У данного алгоритма также есть бинарная версия, которую можно использовать для объединения двух диапазонов в один.
Выходной диапазон может совпадать с одним из входных диапазонов (но не может быть смещен относительно него); однако, если преобразование выполняется «на месте» (in-place), предпочтительнее использовать цикл for на основе диапазона или std::for_each.
Для обоих вариантов доступны версии с поддержкой параллельного выполнения (начиная с C++17) и работы с диапазонами (начиная с C++20).
#include <algorithm>
#include <string>
#include <cctype>
#include <vector>
#include <iterator>
// Копирование с преобразованием:
std::vector<int> in{1, 2, 3, 4, 5, 6, 7};
std::vector<double> out;
std::transform(in.begin(), in.end(),
std::back_inserter(out),
[](int v) { return static_cast<double>(v)/2; });
// out ~= {0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5}
// Объединение двух диапазонов в один:
std::vector<int> in1{1, 2, 3, 4, 5};
std::vector<int> in2{0, 1, 0, 1, 0};
std::vector<int> reduction;
std::transform(in1.begin(), in1.end(), // первый диапазон
in2.begin(), // второй диапазон, количество элементов из первого диапазона
std::back_inserter(reduction),
[](int e1, int e2) { return e1*e2; });
// reduction == {0, 2, 0, 4, 0}
// Выходной диапазон может быть одним из входных диапазонов:
std::string str = "welcome to somewhere";
std::transform(str.begin(), str.end(), // входной диапазон
str.begin(), // Внимание, смещения не может быть
// (только r1.begin(), r2.begin())
[](char c) { return std::toupper(c); });
// str == "WELCOME TO SOMEWHERE"
// Соблюдайте осторожность при работе с типами,
// копирование которых обходится дорого.
struct Expensive{};
std::vector<Expensive> data(10);
std::transform(data.begin(), data.end(),
data.begin(),
[](const Expensive& v) { return v; }); // копирование
// Для изменения элементов "на месте", используйте std::for_each
// или цикл for на основе диапазона.
// В случае с версией для диапазонов, мы можем
// разбить преобразование на два этапа
std::vector<int> two_digit;
std::ranges::transform(in1, in2,
std::back_inserter(two_digit),
std::plus<>{}, // объединение
[](int v) { return v * 10; }, // проекция in1
std::identity{}); // проекция in2
// two_digit == {10, 21, 30, 41, 50}
