std::ranges::transform, std::ranges::unary_transform_result, std::ranges::binary_transform_result
Определено в заголовке | ||
|---|---|---|
| Сигнатура вызова | ||
template< std::input_iterator I, std::sentinel_for<I> S,
std::weakly_incrementable O,
std::copy_constructible F, class Proj = std::identity >
requires std::indirectly_writable
<O, std::indirect_result_t<F&, std::projected<I, Proj>>>
constexpr ranges::unary_transform_result<I, O>
transform( I first1, S last1, O d_first, F unary_op, Proj proj1 = {} );
| (1) | (начиная с C++20) |
template< ranges::input_range R, std::weakly_incrementable O,
std::copy_constructible F, class Proj = std::identity >
requires std::indirectly_writable
<O, std::indirect_result_t
<F&, std::projected<ranges::iterator_t<R>, Proj>>>
constexpr ranges::unary_transform_result<ranges::borrowed_iterator_t<R>, O>
transform( R&& r1, O d_first, F unary_op, Proj proj1 = {} );
| (2) | (начиная с C++20) |
template< std::input_iterator I1, std::sentinel_for<I1> S1,
std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_writable
<O, std::indirect_result_t<F&, std::projected<I1, Proj1>,
std::projected<I2, Proj2>>>
constexpr ranges::binary_transform_result<I1, I2, O>
transform( I1 first1, S1 last1, I2 first2, S2 last2, O d_first,
F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {} );
| (3) | (начиная с C++20) |
template< ranges::input_range R1, ranges::input_range R2,
std::weakly_incrementable O, std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_writable
<O, std::indirect_result_t
<F&, std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>>>
constexpr ranges::binary_transform_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>
transform( R1&& r1, R2&& r2, O d_first,
F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {} );
| (4) | (начиная с C++20) |
template< /*execution-policy*/ Ep,
std::random_access_iterator I, std::sized_sentinel_for<I> S,
std::random_access_iterator O, std::sized_sentinel_for<O> OutS,
std::copy_constructible F, class Proj = std::identity >
requires std::indirectly_writable
<O, std::indirect_result_t<F&, std::projected<I, Proj>>>
ranges::unary_transform_result<I, O>
transform( Ep&& policy, I first1, S last1,
O d_first, OutS d_last, F unary_op, Proj proj1 = {} );
| (5) | (начиная с C++26) |
template< /*execution-policy*/ Ep,
/*sized-random-access-range*/ R, /*sized-random-access-range*/ OutR,
std::copy_constructible F, class Proj = std::identity >
requires std::indirectly_writable
<ranges::iterator_t<OutR>,
std::indirect_result_t
<F&, std::projected<ranges::iterator_t<R>, Proj>>>
ranges::unary_transform_result<ranges::borrowed_iterator_t<R>,
ranges::borrowed_iterator_t<OutR>>
transform( Ep&& policy, R&& r1, OutR&& d_r, F unary_op, Proj proj1 = {} );
| (6) | (начиная с C++26) |
template< /*execution-policy*/ Ep,
std::random_access_iterator I1, std::sized_sentinel_for<I1> S1,
std::random_access_iterator I2, std::sized_sentinel_for<I2> S2,
std::random_access_iterator O, std::sized_sentinel_for<O> OutS,
std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_writable
<O, std::indirect_result_t<F&, std::projected<I1, Proj1>,
std::projected<I2, Proj2>>>
ranges::binary_transform_result<I1, I2, O>
transform( Ep&& policy, I1 first1, S1 last1, I2 first2, S2 last2,
O d_first, OutS d_last, F binary_op,
Proj1 proj1 = {}, Proj2 proj2 = {} );
| (7) | (начиная с C++26) |
template< /*execution-policy*/ Ep,
/*sized-random-access-range*/ R1, sized-random-access-range*/ R2,
/*sized-random-access-range*/ OutR, std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_writable
<ranges::iterator_t<OutR>,
std::indirect_result_t
<F&, std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>>>
ranges::binary_transform_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>,
ranges::borrowed_iterator_t<OutR>>
transform( Ep&& policy, R1&& r1, R2&& r2, OutR&& d_r,
F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {} );
| (8) | (начиная с C++26) |
| Вспомогательные типы | ||
template< class I, class O > using unary_transform_result = ranges::in_out_result<I, O>; | (9) | (начиная с C++20) |
template< class I1, class I2, class O > using binary_transform_result = ranges::in_in_out_result<I1, I2, O>; | (10) | (начиная с C++20) |
Определение /*execution-policy*/ см. на этой странице; определение /*sized-random-access-range*/ см. на этой странице.
Применяет заданную функцию к (проектированным) элементам заданного диапазона (или диапазонов) источника и сохраняет результат в диапазоне назначения.
[d_first, ranges::next(d_first, count)), где count определено ниже.unary_op применяется к каждому из его элементов (спроецированных с помощью proj1).[first1, last1), и count равен ranges::distance(first1, last1).r1, и count равен ranges::distance(r1).binary_op применяется к каждой паре соответствующих элементов (спроецированных с помощью proj1 и proj2 соответственно).[first1, last1) и [first2, last2), а значением count является меньшее из ranges::distance(first1, last1) и ranges::distance(first2, last2).r1 и r2, а значением count является меньшее из ranges::distance(r1) и ranges::distance(r2).policy, и диапазоном назначения является [d_first, d_last) или d_r. Если диапазон назначения исчерпывается до достижения конца любого диапазона-источника, оставшиеся элементы в диапазоне(-ах) источника не будут преобразованы.Если unary_op или binary_op делает недействительным итератор или поддиапазон, либо изменяет элемент в любом из следующих диапазонов, поведение не определено:
-
[first1,last1] -
[r1.begin(),ranges::next(r1.begin(), r1.end())] -
[first2,last2] -
[r2.begin(),ranges::next(r2.begin(), r2.end())] -
[d_first,ranges::next(d_first, count)](countопределено выше) -
[d_first,d_last] -
[d_r.begin(),ranges::next(d_r.begin(), d_r.end())]
Функциональные сущности, описанные на этой странице, представляют собой алгоритмические функциональные объекты (неофициально называемые niebloids), то есть:
- Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
- Ни один из них не видим для поиска, зависящего от аргументов (ADL).
- Когда любой из них обнаруживается с помощью обычного неквалифицированного поиска как имя слева от оператора вызова функции, поиск, зависящий от аргументов, подавляется.
Параметры
| first1, last1 | - | пара итератор-сторож, определяющая первый исходный диапазон |
| r1 | - | первый исходный диапазон |
| first2, last2 | - | пара итератор-сторож, определяющая второй исходный диапазон |
| r2 | - | второй исходный диапазон |
| d_first | - | начало диапазона назначения |
| d_last | - | сторож диапазона назначения |
| d_r | - | диапазон назначения |
| unary_op, binary_op | - | операция, применяемая к спроецированному элементу (элементам) |
| proj1 | - | проекция, применяемая к элементам первого диапазона-источника |
| proj2 | - | проекция, применяемая к элементам второго диапазона-источника |
| policy | - | используемая политика выполнения |
Возвращаемое значение
1,2,5,6) Объект ranges::unary_transform_result, в котором:- Элемент данных
inсодержит итератор, указывающий за последний преобразованный элемент в диапазоне-источнике, или итератор на начало диапазона-источника, если ни один элемент не был преобразован. - Элемент данных
outсодержит итератор, указывающий за последний присвоенный элемент в диапазоне назначения, или итератор на начало диапазона назначения, если ни один элемент не был преобразован.
- Элемент данных
in1содержит итератор, указывающий за последний преобразованный элемент в первом диапазоне-источнике, или итератор на начало первого диапазона-источника, если ни один элемент не был преобразован. - Элемент данных
in2содержит итератор, указывающий за последний преобразованный элемент во втором диапазоне-источнике, или итератор на начало второго диапазона-источника, если ни один элемент не был преобразован. - Элемент данных
outсодержит итератор, указывающий за последний присвоенный элемент в диапазоне назначения, или итератор на начало диапазона назначения, если ни один элемент не был преобразован.
Сложность
При условии, что
- \(\scriptsize N_1\)N1 обозначает
ranges::distance(first1, last1)илиranges::distance(r1), - \(\scriptsize N_2\)N2 обозначает
ranges::distance(first2, last2)илиranges::distance(r2), и - \(\scriptsize N_3\)N3 обозначает
ranges::distance(d_first, d_last)илиranges::distance(d_r):
unary_op и proj1.binary_op, proj1 и proj2.unary_op и proj1.binary_op, proj1 и proj2.Исключения
5-8) Во время выполнения:- Если временные ресурсы памяти, необходимые для параллелизации, недоступны, генерируется исключение
std::bad_alloc. - Если во время доступа к объектам через аргумент алгоритма выбрасывается непойманное исключение, поведение определяется политикой выполнения (для стандартных политик вызывается
std::terminate).
Примечания
ranges::transform не гарантирует последовательное применение unary_op или binary_op. Чтобы применить функцию к последовательности по порядку или чтобы применить функцию, изменяющую элементы последовательности, используйте ranges::for_each.
Возможная реализация
struct transform_fn
{
// First version
template<std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
std::copy_constructible F, class Proj = std::identity>
requires std::indirectly_writable
<O, std::indirect_result_t<F&, std::projected<I, Proj>>>
constexpr ranges::unary_transform_result<I, O>
operator()(I first1, S last1, O d_first, F unary_op, Proj proj1 = {}) const
{
for (; first1 != last1; ++first1, (void)++result)
*result = std::invoke(unary_op, std::invoke(proj1, *first1));
return {std::move(first1), std::move(d_first)};
}
template<ranges::input_range R>
constexpr auto get_end(R&& r)
{
return ranges::end(r);
}
template<ranges::forward_range R>
constexpr auto get_end(R&& r)
{
return ranges::next(ranges::begin(r), ranges::end(r));
}
// Second version
template<ranges::input_range R, std::weakly_incrementable O,
std::copy_constructible F, class Proj = std::identity>
requires std::indirectly_writable<O,
std::indirect_result_t<F&, std::projected<ranges::iterator_t<R>, Proj>>>
constexpr ranges::unary_transform_result<ranges::borrowed_iterator_t<R>, O>
operator()(R&& r1, O d_first, F unary_op, Proj proj1 = {}) const
{
return (*this)(ranges::begin(r1), get_end(r1),
std::move(d_first), std::move(unary_op), std::move(proj1));
}
// Third version
template<std::input_iterator I1, std::sentinel_for<I1> S1,
std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity>
requires std::indirectly_writable
<O, std::indirect_result_t<F&, std::projected<I1, Proj1>,
std::projected<I2, Proj2>>>
constexpr ranges::binary_transform_result<I1, I2, O>
operator()(I1 first1, S1 last1, I2 first2, S2 last2, O d_first,
F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
for (; first1 != last1 && first2 != last2;
++first1, (void)++first2, (void)++result)
*result = std::invoke(binary_op, std::invoke(proj1, *first1),
std::invoke(proj2, *first2));
return {std::move(first1), std::move(first2), std::move(d_first)};
}
// Fourth version
template<ranges::input_range R1, ranges::input_range R2,
std::weakly_incrementable O, std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity>
requires std::indirectly_writable<O,
std::indirect_result_t<F&,
std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>>>
constexpr ranges::binary_transform_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>
operator()(R1&& r1, R2&& r2, O d_first,
F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
return (*this)(ranges::begin(r1), get_end(r1),
ranges::begin(r2), get_end(r2),
std::move(d_first), std::move(binary_op),
std::move(proj1), std::move(proj2));
}
};
inline constexpr transform_fn transform;
|
Пример
В следующем коде используется ranges::transform для преобразования строки на месте в верхний регистр с помощью функции std::toupper, а затем преобразуется каждый char в его порядковое значение. Затем ranges::transform с проекцией используется для преобразования элементов std::vector<Foo> в символы char для заполнения std::string.
#include <algorithm>
#include <cctype>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string s{"hello"};
auto op = [](unsigned char c) -> unsigned char { return std::toupper(c); };
namespace ranges = std::ranges;
// uppercase the string in-place
ranges::transform(s.begin(), s.end(), s.begin(), op);
std::vector<std::size_t> ordinals;
// convert each char to size_t
ranges::transform(s, std::back_inserter(ordinals),
[](unsigned char c) -> std::size_t { return c; });
std::cout << s << ':';
for (auto ord : ordinals)
std::cout << ' ' << ord;
// double each ordinal
ranges::transform(ordinals, ordinals, ordinals.begin(), std::plus{});
std::cout << '\n';
for (auto ord : ordinals)
std::cout << ord << ' ';
std::cout << '\n';
struct Foo { char bar; };
const std::vector<Foo> f = {{'h'},{'e'},{'l'},{'l'},{'o'}};
std::string result;
// project, then uppercase
ranges::transform(f, std::back_inserter(result), op, &Foo::bar);
std::cout << result << '\n';
}
Вывод:
HELLO: 72 69 76 76 79 144 138 152 152 158 HELLO
Смотрите также
| применяет функцию к диапазону элементов, сохраняя результаты в диапазоне назначения (шаблон функции) |
|
|
(C++20) | применяет унарный функциональный объект к элементам из диапазона (алгоритмический функциональный объект) |
|
(C++20) | view последовательности, применяющее функцию преобразования к каждому элементу(шаблон класса) (объект адаптера диапазона) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/ranges/transform