std::ranges::transform, std::ranges::unary_transform_result, std::ranges::binary_transform_result
| Defined in header <algorithm>
|
||
| Call signature |
||
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) | (since 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) | (since 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) | (since 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) | (since 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) | (since 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) | (since 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) | (since 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) | (since C++26) |
| Helper types |
||
template< class I, class O >
using unary_transform_result = ranges::in_out_result<I, O>;
|
(9) | (since C++20) |
template< class I1, class I2, class O >
using binary_transform_result = ranges::in_in_out_result<I1, I2, O>;
|
(10) | (since C++20) |
For the definition of /*execution-policy*/, see this page; for the definition of /*sized-random-access-range*/, see this page.
Applies the given function to the (projected) elements of the given source range(s), and stores the result in the destination range.
[d_first, ranges::next(d_first, count)), where count is defined below.unary_op is applied to each of its elements (projected by proj1).[first1, last1), and count is ranges::distance(first1, last1).r1, and count is ranges::distance(r1).binary_op is applied to each pair of their corresponding elements (projected by proj1 and proj2 respectively).[first1, last1) and [first2, last2), and count is the lesser of ranges::distance(first1, last1) and ranges::distance(first2, last2).r1 and r2, and count is the lesser of ranges::distance(r1) and ranges::distance(r2).policy, and the destination range is [d_first, d_last) or d_r. If the destination range is exhausted before reaching the end of any source range, the remaining elements in the source range(s) will not be transformed.If unary_op or binary_op invalidates an iterator or subrange, or modifies an element in any of the following ranges, the behavior is undefined:
[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)](countis defined above)[d_first,d_last][d_r.begin(),ranges::next(d_r.begin(), d_r.end())]
The function-like entities described on this page are algorithm function objects (informally known as niebloids), that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
Parameters
| first1, last1 | - | the iterator-sentinel pair defining the first source range |
| r1 | - | the first source range |
| first2, last2 | - | the iterator-sentinel pair defining the second source range |
| r2 | - | the second source range |
| d_first | - | the beginning of the destination range |
| d_last | - | the sentinel of the destination range |
| d_r | - | the destination range |
| unary_op, binary_op | - | operation to apply to the projected element(s) |
| proj1 | - | the projection to be applied to the elements in the first source range |
| proj2 | - | the projection to be applied to the elements in the second source range |
| policy | - | the execution policy to use |
Return value
ranges::unary_transform_result object where:
- The data member
inholds the an iterator past the last transformed element in the source range, or an iterator to the beginning of the source range if no element is transformed. - The data member
outholds the an iterator past the last assigned element in the destination range, or an iterator to the beginning of the destination range if no element is transformed.
ranges::binary_transform_result object where:
- The data member
in1holds the an iterator past the last transformed element in the first source range, or an iterator to the beginning of the first source range if no element is transformed. - The data member
in2holds the an iterator past the last transformed element in the second source range, or an iterator to the beginning of the second source range if no element is transformed. - The data member
outholds the an iterator past the last assigned element in the destination range, or an iterator to the beginning of the destination range if no element is transformed.
Complexity
Given
- N1 as
ranges::distance(first1, last1)orranges::distance(r1), - N2 as
ranges::distance(first2, last2)orranges::distance(r2), and - N3 as
ranges::distance(d_first, d_last)orranges::distance(d_r):
unary_op and proj1.binary_op, proj1 and proj2.unary_op and proj1.binary_op, proj1 and proj2.Exceptions
- If the temporary memory resources required for parallelization are not available, std::bad_alloc is thrown.
- If an uncaught exception is thrown while accessing objects via an algorithm argument, the behavior is determined by the execution policy (for standard policies, std::terminate is invoked).
Notes
ranges::transform does not guarantee in-order application of unary_op or binary_op. To apply a function to a sequence in-order or to apply a function that modifies the elements of a sequence, use ranges::for_each.
Possible implementation
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;
|
Example
The following code uses ranges::transform to convert a string in place to uppercase using the std::toupper function and then transforms each char to its ordinal value.
Then ranges::transform with a projection is used to transform elements of std::vector<Foo> into chars to fill a 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';
}
Output:
HELLO: 72 69 76 76 79
144 138 152 152 158
HELLO
See also
| applies a function to a range of elements, storing results in a destination range (function template) | |
(C++20) |
applies a unary function object to elements from a range (algorithm function object) |
| a view of a sequence that applies a transformation function to each element (class template) (range adaptor object) |