Understanding std::transform_reduce in Modern C++


Understanding std::transform_reduce in Modern C++

std::transform_reduce is a powerful C++17 algorithm that combines the functionality of transform and reduce (or accumulate) in a single pass. It allows you to apply a transformation to elements and then reduce them using a binary operation, which can help write concise and efficient code.

Syntax

template<class InputIt1, class InputIt2, class T,
         class BinaryOp1, class BinaryOp2>
T transform_reduce(InputIt1 first1, InputIt1 last1,
                   InputIt2 first2, T init,
                   BinaryOp1 binary_op1,
                   BinaryOp2 binary_op2);

template<class InputIt, class T,
         class BinaryOp1, class UnaryOp>
T transform_reduce(InputIt first, InputIt last,
                   T init,
                   BinaryOp1 binary_op1,
                   UnaryOp unary_op);

In simple words:

  • It applies a unary transformation to each element (optional).
  • Then it reduces all results using a binary operation like sum, product, or custom combination.
  • It can work in parallel with execution policies in C++17/20.

Example 1: Sum of squares

#include <iostream>
#include <vector>
#include <numeric>
#include <execution>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    int sum_of_squares = std::transform_reduce(
        std::execution::seq,   // sequential execution
        numbers.begin(),
        numbers.end(),
        0,                     // initial value
        std::plus<>(),    // binary operation (sum)
        [](int x){ return x*x; } // unary transform (square)
    );

    std::cout << "Sum of squares: " << sum_of_squares << std::endl;
    return 0;
}

Example 2: Dot product of two vectors

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> a = {1, 2, 3};
    std::vector<int> b = {4, 5, 6};

    int dot_product = std::transform_reduce(
        a.begin(), a.end(),
        b.begin(),
        0  // initial value
    );

    std::cout << "Dot product: " << dot_product << std::endl;
    return 0;
}

Example 3: Parallel transform_reduce

#include <iostream>
#include <vector>
#include <numeric>
#include <execution>

int main() {
    std::vector<double> numbers(1'000'000, 1.5);

    double sum = std::transform_reduce(
        std::execution::par,  // parallel execution
        numbers.begin(),
        numbers.end(),
        0.0
    );

    std::cout << "Parallel sum: " << sum << std::endl;
    return 0;
}

Key Points

  • transform_reduce avoids creating an intermediate container for the transformed values.
  • It supports sequential and parallel execution policies.
  • Two main forms: single range with unary transform, or two ranges for pairwise operations (like dot product).
  • Initial value is required to correctly handle empty ranges.

Using std::transform_reduce can make your code cleaner and more efficient, especially for large datasets or parallel computation scenarios.

C/C++ Programming

–EOF (The Ultimate Computing & Technology Blog) —

549 words
Last Post: WordPress: How to Output Full Text in the Feed?
Next Post: ChatGPT: New Image Creation (art school)

The Permanent URL is: Understanding std::transform_reduce in Modern C++ (AMP Version)

Leave a Reply