Spec-Zone.ru › C++

std::transform

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

Пусть count равно std::distance(first1, last1). Применяет заданную функцию к элементам заданного исходного диапазона (или диапазонов) и сохраняет результат в целевом диапазоне [d_first, std::next(d_first, count)).

1) Имеется только один исходный диапазон [first1, last1), и унарная операция unary_op применяется к каждому из его элементов.
Если unary_op делает недействительным итератор или изменяет элемент в любом из следующих диапазонов, поведение не определено:
  • [first1, last1]
  • [d_first, std::next(d_first, count)]
2) Имеются два исходных диапазона [first1, last1) и [first2, std::next(first2, count)), и бинарная операция binary_op применяется к каждой паре соответствующих элементов.
Если binary_op делает недействительным итератор или изменяет элемент в любом из следующих диапазонов, поведение не определено:
  • [first1, last1]
  • [first2, std::next(first2, count)]
  • [d_first, std::next(d_first, count)]
3,4) То же, что и (1,2), но выполняется в соответствии с policy.
Эти перегрузки участвуют в разрешении перегрузок только в том случае, если значение следующего выражения равно true:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(с C++20)

Параметры

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

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

Retfun(constType&a);

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

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

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

Retfun(constType1&a,constType2&b);

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

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

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

Итератор, указывающий за пределы последнего элемента целевого диапазона (past-the-end).

Сложность

Пусть \(\scriptsize N\)N равно std::distance(first1, last1):

1,3) Ровно \(\scriptsize N\)N применений unary_op.
2,4) Ровно \(\scriptsize N\)N применений binary_op.

Исключения

3,4) В процессе выполнения:
  • Если временные ресурсы памяти, необходимые для параллелизации, недоступны, выбрасывается std::bad_alloc.
  • Если при доступе к объектам через аргумент алгоритма выбрасывается неперехваченное исключение, поведение определяется политикой выполнения (для стандартных политик вызывается std::terminate).

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

transform (1)
template<class InputIt, class OutputIt, class UnaryOp>
constexpr //< since C++20
OutputIt transform(InputIt first1, InputIt last1,
                   OutputIt d_first, UnaryOp unary_op)
{
    for (; first1 != last1; ++d_first, ++first1)
        *d_first = unary_op(*first1);
    
    return d_first;
}
transform (2)
template<class InputIt1, class InputIt2, 
         class OutputIt, class BinaryOp>
constexpr //< since C++20
OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2,
                   OutputIt d_first, BinaryOp binary_op)
{
    for (; first1 != last1; ++d_first, ++first1, ++first2)
        *d_first = binary_op(*first1, *first2);
    
    return d_first;
}

Примечания

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

Пример

#include <algorithm>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

void print_ordinals(const std::vector<unsigned>& ordinals)
{
    std::cout << "ordinals: ";
    for (unsigned ord : ordinals)
        std::cout << std::setw(3) << ord << ' ';
    std::cout << '\n';
}

char to_uppercase(unsigned char c)
{
    return std::toupper(c);
}

void to_uppercase_inplace(char& c)
{
    c = to_uppercase(c);
}

// Transform string to uppercase in-place
void unary_transform_example(std::string& hello, std::string world)
{
    std::transform(hello.cbegin(), hello.cend(), hello.begin(), to_uppercase);
    std::cout << "hello = " << std::quoted(hello) << '\n';
    
    // for_each version (see Notes above)
    std::for_each(world.begin(), world.end(), to_uppercase_inplace);
    std::cout << "world = " << std::quoted(world) << '\n';
}

// Transform numbers to doubled values
void binary_transform_example(std::vector<unsigned> ordinals)
{
    print_ordinals(ordinals);
    
    std::transform(ordinals.cbegin(), ordinals.cend(), ordinals.cbegin(),
                   ordinals.begin(), std::plus<>{});
    
    print_ordinals(ordinals);
}

int main()
{
    std::string hello("hello");
    unary_transform_example(hello, "world");
    
    std::vector<unsigned> ordinals;
    std::copy(hello.cbegin(), hello.cend(), std::back_inserter(ordinals));
    binary_transform_example(std::move(ordinals));
}

Вывод:

hello = "HELLO"
world = "WORLD"
ordinals:  72  69  76  76  79 
ordinals: 144 138 152 152 158

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

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

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

Смотрите также

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

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

Spec-Zone.ru

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