C++17stladvanced
std::transform_reduce
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
Combines a transformation and a reduction into a single operation, supporting parallel execution. It is the parallel-friendly equivalent of a map-reduce pattern.
Real-World Scenario
Compute the dot product of two vectors in a machine learning library.
Quick Snippet
snippet.cpp
#include <numeric>
#include <vector>
std::vector<double> a = {1.0, 2.0, 3.0};
std::vector<double> b = {4.0, 5.0, 6.0};
double dot = std::transform_reduce(a.begin(), a.end(), b.begin(), 0.0);
// 1*4 + 2*5 + 3*6 = 32.0Full Example
transform_reduce.cpp
// CodeNebula - C++17 Example: std::transform_reduce
// Compile: g++ -std=c++17 -Wall -Wextra -o example transform_reduce.cpp
// Demonstrates std::transform_reduce, which fuses a transformation step with
// a reduction step. It applies a unary or binary transform to elements, then
// reduces the results. This is more efficient than separate transform + reduce
// calls and is parallelizable.
#include <iostream>
#include <numeric>
#include <vector>
#include <string>
#include <functional>
#include <cmath>
int main()
{
// ------------------------------------------------------------------
// 1. Dot product (binary transform_reduce): multiply pairs, then sum
// ------------------------------------------------------------------
std::cout << "=== dot product (binary form) ===" << std::endl;
std::vector<double> a = {1.0, 2.0, 3.0, 4.0};
std::vector<double> b = {5.0, 6.0, 7.0, 8.0};
// init + reduce(transform(a[i], b[i]))
// = 0 + (1*5) + (2*6) + (3*7) + (4*8) = 70
double dot = std::transform_reduce(
a.begin(), a.end(), b.begin(),
0.0 // init
); // default: multiply pairs, then sum
std::cout << " a = {1,2,3,4}, b = {5,6,7,8}" << std::endl;
std::cout << " dot product = " << dot << std::endl;
// ------------------------------------------------------------------
// 2. Sum of squares (unary transform_reduce)
// ------------------------------------------------------------------
std::cout << "\n=== sum of squares (unary form) ===" << std::endl;
std::vector<int> v = {1, 2, 3, 4, 5};
int sum_sq = std::transform_reduce(
v.begin(), v.end(),
0, // init
std::plus<>{}, // reduce operation
[](int x) { return x * x; } // transform
);
std::cout << " v = {1,2,3,4,5}" << std::endl;
std::cout << " sum of squares = " << sum_sq << std::endl;
// ------------------------------------------------------------------
// 3. Euclidean distance
// ------------------------------------------------------------------
std::cout << "\n=== euclidean distance ===" << std::endl;
std::vector<double> p1 = {1.0, 2.0, 3.0};
std::vector<double> p2 = {4.0, 6.0, 3.0};
double dist_sq = std::transform_reduce(
p1.begin(), p1.end(), p2.begin(),
0.0, // init
std::plus<>{}, // reduce: sum
[](double x, double y) { return (x - y) * (x - y); } // transform
);
std::cout << " p1 = {1,2,3}, p2 = {4,6,3}" << std::endl;
std::cout << " distance = " << std::sqrt(dist_sq) << std::endl;
// ------------------------------------------------------------------
// 4. Count elements matching a predicate
// ------------------------------------------------------------------
std::cout << "\n=== count matching ===" << std::endl;
std::vector<int> scores = {85, 92, 67, 91, 78, 95, 88};
int passing = std::transform_reduce(
scores.begin(), scores.end(),
0,
std::plus<>{},
[](int s) { return s >= 80 ? 1 : 0; }
);
std::cout << " scores: ";
for (int s : scores) std::cout << s << " ";
std::cout << std::endl;
std::cout << " passing (>=80): " << passing << std::endl;
// ------------------------------------------------------------------
// 5. Total string length
// ------------------------------------------------------------------
std::cout << "\n=== total string length ===" << std::endl;
std::vector<std::string> words = {"hello", "world", "foo", "bar"};
std::size_t total_len = std::transform_reduce(
words.begin(), words.end(),
std::size_t{0},
std::plus<>{},
[](const std::string& s) { return s.size(); }
);
std::cout << " words: hello, world, foo, bar" << std::endl;
std::cout << " total length = " << total_len << std::endl;
// ------------------------------------------------------------------
// 6. Weighted sum
// ------------------------------------------------------------------
std::cout << "\n=== weighted sum ===" << std::endl;
std::vector<double> values = {10.0, 20.0, 30.0};
std::vector<double> weights = {0.2, 0.3, 0.5};
double weighted = std::transform_reduce(
values.begin(), values.end(), weights.begin(),
0.0 // default: multiply pairs, then sum
);
std::cout << " values: 10, 20, 30" << std::endl;
std::cout << " weights: 0.2, 0.3, 0.5" << std::endl;
std::cout << " weighted sum = " << weighted << std::endl;
return 0;
}
/*
Expected output:
=== dot product (binary form) ===
a = {1,2,3,4}, b = {5,6,7,8}
dot product = 70
=== sum of squares (unary form) ===
v = {1,2,3,4,5}
sum of squares = 55
=== euclidean distance ===
p1 = {1,2,3}, p2 = {4,6,3}
distance = 5
=== count matching ===
scores: 85 92 67 91 78 95 88
passing (>=80): 5
=== total string length ===
words: hello, world, foo, bar
total length = 16
=== weighted sum ===
values: 10, 20, 30
weights: 0.2, 0.3, 0.5
weighted sum = 23
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example transform_reduce.cpp