Если views::filter решает, какие элементы обработать, то
views::transform — во что их превратить. Никакого копирования: это такая же ленивая обёртка над данными.🌸 Базовое использование
#include <ranges>
#include <vector>
#include <string>
namespace views = std::views;
std::vector<std::string> words = {"hello", "world", "cpp"};
// Получаем длины слов
auto lengths = words | views::transform([](const std::string& s) {
return s.size();
});
// При итерации: 5, 5, 3
Лямбда применяется к каждому элементу в момент итерации — ни раньше, ни позже.
🍪 Трансформация с изменением типа
transform не обязан возвращать тот же тип. Из string можно получить size_t, из double — int, из структуры — одно из её полей:// Верхний регистр (#include <cctype>)
auto upper = words | views::transform([](std::string s) {
for (char& c : s) c = std::toupper(c);
return s;
});
// При итерации: "HELLO", "WORLD", "CPP"
Обратите внимание: здесь s принимается по значению — это намеренная копия, которую мы модифицируем.
🍀 filter + transform — классика
Главная сила адаптеров — в их цепочке. Сначала отсеиваем ненужное, потом преобразуем то, что осталось:
struct Employee {
std::string name;
double salary;
bool is_active;
};
std::vector<Employee> employees = {
{"Алиса", 80000, true},
{"Борис", 95000, false},
{"Виктор", 72000, true},
{"Галина", 110000, true},
};
// Имена активных сотрудников с зарплатой выше 75 000
auto high_earners = employees
| views::filter([](const Employee& e) { return e.is_active; })
| views::filter([](const Employee& e) { return e.salary > 75000; })
| views::transform([](const Employee& e) { return e.name; });
for (const auto& name : high_earners) {
std::cout << name << "\n"; // Алиса, Галина
}Весь конвейер ленив: ни одна лямбда не вызывается, пока не начнётся итерация.
🌱 pipe-синтаксис vs явный тип
auto v1 = words | views::transform([](const std::string& s) { return s.size(); });
auto v2 = std::ranges::transform_view{words, [](const std::string& s) { return s.size(); }};🍙 Материализация в вектор
transform_view — не контейнер. Чтобы получить std::vector, нужно явно материализовать:// C++23
auto vec = words | views::transform([](const std::string& s) { return s.size(); })
| std::ranges::to<std::vector>();
// C++20
std::vector<size_t> vec(lengths.begin(), lengths.end());
❌ Ловушка: несовпадение типа возврата
// UB — возвращается ссылка на временный объект
auto bad = words | views::transform([](const std::string& s) -> const std::string& {
std::string upper = s;
return upper; // dangling reference!
});
// Правильно — возвращаем по значению
auto ok = words | views::transform([](const std::string& s) {
std::string upper = s;
for (char& c : upper) c = std::toupper(c);
return upper;
});
🐸 Продолжение следует...
📍Навигация: Вакансии • Задачи • Собесы
Библиотека C/C++ разработчика
#константная_правильность