Spec-Zone.ru › C++

std::transform

Определено в заголовке <algorithm>
(1)
template< class InputIt, class OutputIt, class UnaryOperation >
OutputIt transform( InputIt first1, InputIt last1,
                    OutputIt d_first, UnaryOperation unary_op );
(до C++20)
template< class InputIt, class OutputIt, class UnaryOperation >
constexpr OutputIt transform( InputIt first1, InputIt last1,
                              OutputIt d_first, UnaryOperation unary_op );
(с C++20)
template< class ExecutionPolicy, class ForwardIt1,
          class ForwardIt2, class UnaryOperation >
ForwardIt2 transform( ExecutionPolicy&& policy,
                      ForwardIt1 first1, ForwardIt1 last1,
                      ForwardIt2 d_first, UnaryOperation unary_op );
(2) (с C++17)
(3)
template< class InputIt1, class InputIt2,
          class OutputIt, class BinaryOperation >
OutputIt transform( InputIt1 first1, InputIt1 last1, InputIt2 first2,
                    OutputIt d_first, BinaryOperation binary_op );
(до C++20)
template< class InputIt1, class InputIt2,
          class OutputIt, class BinaryOperation >
constexpr OutputIt transform( InputIt1 first1, InputIt1 last1, InputIt2 first2,
                              OutputIt d_first, BinaryOperation binary_op );
(с C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
          class ForwardIt3, class BinaryOperation >
ForwardIt3 transform( ExecutionPolicy&& policy,
                      ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2,
                      ForwardIt3 d_first, BinaryOperation binary_op );
(4) (с C++17)

std::transform применяет заданную функцию к диапазону и сохраняет результат в другом диапазоне, сохраняя порядок исходных элементов и начиная с d_first.

1) Унарная операция unary_op применяется к диапазону, определенному [first1, last1).
3) Бинарная операция binary_op применяется к парам элементов из двух диапазонов: один определен [first1, last1) и другой начинается с first2.
2,4) То же, что (1,3), но выполняется согласно policy. Эти перегрузки не участвуют в разрешении перегрузки, если

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> является true.

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> является true.

(с C++20)

unary_op и binary_op не должны делать недействительными итераторы, включая конечные итераторы, или изменять любые элементы вовлечённых диапазонов.

Параметры

first1, last1 - первый диапазон элементов для преобразования
first2 - начало второго диапазона элементов для преобразования
d_first - начало целевого диапазона, может быть равно first1 или first2
policy - политика выполнения, используемая. Подробности см. в политике выполнения.
unary_op - унарная функция-объект операции, которая будет применена.

Подпись функции должна быть эквивалентной следующей:

Ret fun(const Type &a);

Подпись не обязана иметь const &.
Тип Type должен быть таким, чтобы объект типа InputIt мог быть обращен к значению и затем неявно преобразован к Type. Тип Ret должен быть таким, чтобы объект типа OutputIt мог быть обращен к значению и присвоен значение типа Ret. ​

binary_op - бинарная функция-объект операции, которая будет применена.

Подпись функции должна быть эквивалентной следующей:

Ret fun(const Type1 &a, const Type2 &b);

Подпись не обязана иметь const &.
Типы Type1 и Type2 должны быть такими, чтобы объекты типов InputIt1 и InputIt2 могли быть обращены к значению и затем неявно преобразованны к Type1 и Type2 соответственно. Тип Ret должен быть таким, чтобы объект типа OutputIt мог быть обращен к значению и присвоен значение типа Ret. ​

Требования к типу
-InputIt, InputIt1, InputIt2 должен соответствовать требованиям LegacyInputIterator.
-OutputIt должен соответствовать требованиям LegacyOutputIterator.
-ForwardIt1, ForwardIt2, ForwardIt3 должен соответствовать требованиям LegacyForwardIterator.

Возвращаемое значение

Итератор вывода к элементу, следующему за последним преобразованным элементом.

Сложность

1,2) Ровно std::distance(first1, last1) применений unary_op.
3,4) Ровно std::distance(first1, last1) применений binary_op.

Исключение

Перегрузки с параметром шаблона ExecutionPolicy сообщают об ошибках следующим образом:

  • Если выполнение функции, вызванной в рамках алгоритма, вызывает исключение и ExecutionPolicy — одна из стандартных политик, то вызывается std::terminate. Для любой другой ExecutionPolicy, поведение определяется реализацией.
  • Если алгоритм не может выделить память, бросается std::bad_alloc.

Возможная реализация

transform (1)
template<class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1,
                   OutputIt d_first, UnaryOperation unary_op)
{
    while (first1 != last1)
        *d_first++ = unary_op(*first1++);
 
    return d_first;
}
transform (3)
template<class InputIt1, class InputIt2, 
         class OutputIt, class BinaryOperation>
OutputIt transform(InputIt1 first1, InputIt1 last1,
                   InputIt2 first2, OutputIt d_first,
                   BinaryOperation binary_op)
{
    while (first1 != last1)
        *d_first++ = binary_op(*first1++, *first2++);
 
    return d_first;
}

Примечания

std::transform не гарантирует порядок применения unary_op или binary_op. Чтобы применить функцию к последовательности в порядке следования или применить функцию, которая изменяет элементы последовательности, используйте std::for_each.

Пример

Следующий код использует transform для преобразования строки в верхний регистр на месте, используя функцию std::toupper и затем преобразует каждый char в его порядковое значение:

#include <algorithm>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
 
void print_ordinals(std::vector<std::size_t> const& ordinals)
{
    std::cout << "ordinals: ";
    for (std::size_t ord : ordinals)
        std::cout << std::setw(3) << ord << ' ';
    std::cout << '\n';
}
 
int main()
{
    std::string s{"hello"};
    std::transform(s.cbegin(), s.cend(),
                   s.begin(), // write to the same location
                   [](unsigned char c) { return std::toupper(c); });
    std::cout << "s = " << std::quoted(s) << '\n';
 
    // achieving the same with std::for_each (see Notes above)
    std::string g{"hello"};
    std::for_each(g.begin(), g.end(), [](char& c) // modify in-place
    {
        c = std::toupper(static_cast<unsigned char>(c));
    });
    std::cout << "g = " << std::quoted(g) << '\n';
 
    std::vector<std::size_t> ordinals;
    std::transform(s.cbegin(), s.cend(), std::back_inserter(ordinals),
                   [](unsigned char c) { return c; });
 
    print_ordinals(ordinals);
 
    std::transform(ordinals.cbegin(), ordinals.cend(), ordinals.cbegin(),
                   ordinals.begin(), std::plus<>{});
 
    print_ordinals(ordinals);
}

Вывод:

s = "HELLO"
g = "HELLO"
ordinals:  72  69  76  76  79 
ordinals: 144 138 152 152 158

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение как опубликовано Правильное поведение
LWG 242 C++98 unary_op и binary_op не могут иметь побочных эффектов они не могут изменять вовлеченные диапазоны

См. также

for_each
применяет функцию к диапазону элементов
(шаблон функции)
ranges::transform
(C++20)
применяет функцию к диапазону элементов
(неблочный)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/algorithm/transform

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API