std::transform_reduce(3)

NAME
std::transform_reduce - std::transform_reduce

Synopsis
   Defined in header <numeric>
   template< class InputIt1, class
   InputIt2, class T >
   T transform_reduce( InputIt1 (since C++17)
   first1, InputIt1 last1, (until C++20)
   InputIt2 first2,
   T init );
   template< class InputIt1, class
   InputIt2, class T >
   constexpr
   T transform_reduce( InputIt1 (since C++20)
   first1, InputIt1 last1,
   InputIt2 first2,
   T init );
   template< class InputIt1, class
   InputIt2,
   class T,
   class BinaryReductionOp,
   class BinaryTransformOp > (since C++17)
   T transform_reduce( InputIt1 (until C++20)
   first1, InputIt1 last1,
   InputIt2 first2,
   T init,
   BinaryReductionOp reduce,
   BinaryTransformOp transform );
   template< class InputIt1, class
   InputIt2,
   class T,
   class BinaryReductionOp,
   class BinaryTransformOp >
   constexpr (since C++20)
   T transform_reduce( InputIt1
   first1, InputIt1 last1,
   InputIt2 first2,
   T init,
   BinaryReductionOp reduce,
   BinaryTransformOp transform );
   template< class InputIt,
   class T,
   class BinaryReductionOp,
   class UnaryTransformOp > (since C++17)
   T transform_reduce( InputIt first, (until C++20)
   InputIt last,
   T init, (1)
   BinaryReductionOp reduce,
   UnaryTransformOp transform );
   template< class InputIt, class T,
   class BinaryReductionOp,
   class UnaryTransformOp >
   constexpr
   T transform_reduce( InputIt first, (2) (since C++20)
   InputIt last,
   T init,
   BinaryReductionOp reduce,
   UnaryTransformOp transform );
   template< class ExecutionPolicy,
   class ForwardIt1, class
   ForwardIt2, class T >
   T transform_reduce(
   ExecutionPolicy&& policy, (4) (since C++17)
   ForwardIt1 first1, ForwardIt1
   last1, (3)
   ForwardIt2 first2,
   T init );
   template< class ExecutionPolicy,
   class ForwardIt1, class
   ForwardIt2, class T,
   class BinaryReductionOp,
   class BinaryTransformOp >
   T transform_reduce(
   ExecutionPolicy&& policy, (5) (since C++17)
   ForwardIt1 first1, ForwardIt1
   last1,
   ForwardIt2 first2,
   T init,
   BinaryReductionOp reduce,
   BinaryTransformOp transform );
   template< class ExecutionPolicy,
   class ForwardIt, class T,
   class BinaryReductionOp,
   class UnaryTransformOp >
   T transform_reduce( (6) (since C++17)
   ExecutionPolicy&& policy,
   ForwardIt first, ForwardIt last,
   T init,
   BinaryReductionOp reduce,
   UnaryTransformOp transform );
   1) Equivalent to std::transform_reduce(first1, last1, first2, init, std::plus<>(),
   std::multiplies<>());, effectively parallelized version of the default
   std::inner_product
   2) Applies transform to each pair of elements from the ranges [first; last) and the
   range starting at first2 and reduces the results (possibly permuted and aggregated
   in unspecified manner) along with the initial value init over reduce
   3) Applies transform to each element in the range [first; last) and reduces the
   results (possibly permuted and aggregated in unspecified manner) along with the
   initial value init over reduce.
   4-6) Same as (1-3), but executed according to policy. These overloads do not
   participate in overload resolution unless
   std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>
   (until C++20)
   std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>
   (since C++20) is true.
   The behavior is non-deterministic if reduce is not associative or not commutative.
   The behavior is undefined if reduce, or transform modifies any element or
   invalidates any iterator in the input ranges, including their end iterators.

Parameters
   first, last - the range of elements to apply the algorithm to
   init - the initial value of the generalized sum
   policy - the execution policy to use. See execution policy
                        for details.
                        binary FunctionObject that will be applied in
   reduce - unspecified order to the results of transform, the
                        results of other reduce and init.
                        unary or binary FunctionObject that will be
   transform - applied to each element of the input range(s). The
                        return type must be acceptable as input to reduce

Type requirements
   -
   T must meet the requirements of MoveConstructible in order to use overloads (3,6).
   and the result of the expressions reduce(init, transform(*first)),
   reduce(transform(*first), init), reduce(init, init), and reduce(transform(*first),
   transform(*first)) must be convertible to T
   -
   T must meet the requirements of MoveConstructible in order to use overloads (2,5).
   and the result of the expressions reduce(init, transform(*first1, *first2)),
   reduce(transform(*first1, *first2), init), reduce(init, init), and
   reduce(transform(*first1, *first2), transform(*first1, *first2)) must be convertible
   to T
   -
   InputIt must meet the requirements of LegacyInputIterator.
   -
   ForwardIt must meet the requirements of LegacyForwardIterator.

Return value
   2) Generalized sum of init and transform(*first,*first2),
   transform(*(first+1),*(first2+1)), ..., over reduce
   3) Generalized sum of init and transform(*first), transform(*(first+1)), ...
   transform(*(last-1)) over reduce,
   where generalized sum GSUM(op, a
   1, ..., a
   N) is defined as follows:
     * if N=1, a
       1
     * if N > 1, op(GSUM(op, b
       1, ..., b
       K), GSUM(op, b
       M, ..., b
       N)) where
              * b
                1, ..., b
                N may be any permutation of a1, ..., aN and
              * 1 < K+1 = M ≤ N
   in other words, the results of transform or of reduce may be grouped and arranged in
   arbitrary order.

Complexity
   1,2,4,5) O(last1 - first1) applications each of reduce and transform.
   3,6) O(last - first) applications each of transform and reduce.

Exceptions
   The overloads with a template parameter named ExecutionPolicy report errors as
   follows:
     * If execution of a function invoked as part of the algorithm throws an exception
       and ExecutionPolicy is one of the standard policies, std::terminate is called.
       For any other ExecutionPolicy, the behavior is implementation-defined.
     * If the algorithm fails to allocate memory, std::bad_alloc is thrown.

Notes
   In the unary-binary overload (3,6), transform is not applied to init
   If first == last or first1 == last1, init is returned, unmodified

Example
   transform_reduce can be used to parallelize std::inner_product: // Run this code
 #include <algorithm>
 #include <execution>
 #include <iostream>
 #include <iterator>
 #include <locale>
 #include <numeric>
 #include <vector>
 // to parallelize non-associate accumulative operation, you'd better choose
 // transform_reduce instead of reduce; e.g., a + b * b != b + a * a
 void print_sum_squared(long const num)
 {
     std::cout.imbue(std::locale{"en_US.UTF8"});
     std::cout << "num = " << num << '\n';
     // create an immutable vector filled with pattern: 1,2,3,4, 1,2,3,4 ...
     const std::vector<long> v { [n = num * 4] {
         std::vector<long> v;
         v.reserve(n);
         std::generate_n(std::back_inserter(v), n, [i=0]() mutable { return 1 + i++ % 4; });
         return v;
     }()};
     auto squared_sum = [](auto sum, auto val) { return sum + val * val; };
     auto sum1 = std::accumulate(v.cbegin(), v.cend(), 0L, squared_sum);
     std::cout << "accumulate(): " << sum1 << '\n';
     auto sum2 = std::reduce(std::execution::par, v.cbegin(), v.cend(), 0L, squared_sum);
     std::cout << "reduce(): " << sum2 << '\n';
     auto sum3 = std::transform_reduce(std::execution::par, v.cbegin(), v.cend(), 0L,
                        std::plus{},
                        [](auto val) { return val * val; });
     std::cout << "transform_reduce(): " << sum3 << '\n';
     std::cout << '\n';
 }
 int main()
 {
     print_sum_squared(1);
     print_sum_squared(1'000);
     print_sum_squared(1'000'000);
 }

Possible output:
 num = 1
 accumulate(): 30
 reduce(): 30
 transform_reduce(): 30
 num = 1,000
 accumulate(): 30,000
 reduce(): -7,025,681,278,312,630,348
 transform_reduce(): 30,000
 num = 1,000,000
 accumulate(): 30,000,000
 reduce(): -5,314,886,882,370,003,032
 transform_reduce(): 30,000,000

See also
   accumulate sums up a range of elements
              (function template)
              applies a function to a range of elements, storing results in a
   transform destination range
              (function template)
   reduce similar to std::accumulate, except out of order
   (C++17) (function template)