Namespaces
Variants

std::ranges::transform, std::ranges::unary_transform_result, std::ranges::binary_transform_result

From cppreference.com
 
 
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Non-modifying sequence operations    
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17)(C++11)
(C++20)(C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
(C++11)    

Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
(C++11)
(C++17)
Lexicographical comparison operations
Permutation operations


 
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Fold operations (Helper templates)
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
       
       
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
       
       
Permutation operations
Specialized <memory> algorithms
Return types
 
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.

1-4) The destination range is [d_firstranges::next(d_first, count)), where count is defined below.
1,2) There is only one source range, and the unary operation unary_op is applied to each of its elements (projected by proj1).
1) The source range is [first1last1), and count is ranges::distance(first1, last1).
2) The source range is r1, and count is ranges::distance(r1).
3,4) There are two source ranges, and the binary operation binary_op is applied to each pair of their corresponding elements (projected by proj1 and proj2 respectively).
3) The two source ranges are [first1last1) and [first2last2), and count is the lesser of ranges::distance(first1, last1) and ranges::distance(first2, last2).
4) The two source ranges are r1 and r2, and count is the lesser of ranges::distance(r1) and ranges::distance(r2).
5-8) Same as (1-4), but executed according to policy, and the destination range is [d_firstd_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:

  • [first1last1]
  • [r1.begin()ranges::next(r1.begin(), r1.end())]
  • [first2last2]
  • [r2.begin()ranges::next(r2.begin(), r2.end())]
  • [d_firstranges::next(d_first, count)] (count is defined above)
  • [d_firstd_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:

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

1,2,5,6) A ranges::unary_transform_result object where:
  • The data member in holds 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 out holds 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.
3,4,7,8) A ranges::binary_transform_result object where:
  • The data member in1 holds 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 in2 holds 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 out holds 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) or ranges::distance(r1),
  • N2 as ranges::distance(first2, last2) or ranges::distance(r2), and
  • N3 as ranges::distance(d_first, d_last) or ranges::distance(d_r):
1,2) Exactly N1 applications of unary_op and proj1.
3,4) Exactly min(N1,N2) applications of binary_op, proj1 and proj2.
5,6) Exactly min(N1,N3) applications of unary_op and proj1.
7,8) Exactly min(N1,N2,N3) applications of binary_op, proj1 and proj2.

Exceptions

5-8) During the execution process:
  • 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) [edit]
applies a unary function object to elements from a range
(algorithm function object)[edit]
a view of a sequence that applies a transformation function to each element
(class template) (range adaptor object)[edit]