C++17stladvanced
std::transform_exclusive_scan
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
Applies a unary transformation to each element and computes an exclusive prefix sum (shifted by one, starting with the identity). Supports parallel execution.
Real-World Scenario
Compute memory offsets for a list of objects where each object's serialized size must be squared for alignment purposes.
Quick Snippet
snippet.cpp
#include <numeric>
#include <vector>
std::vector<int> values = {1, 2, 3, 4};
std::vector<int> result(values.size());
std::transform_exclusive_scan(values.begin(), values.end(), result.begin(),
0, std::plus<>{}, [](int x) { return x * x; });
// result: {0, 1, 5, 14} (0, 0+1, 0+1+4, 0+1+4+9)Full Example
transform_exclusive_scan.cpp
// CodeNebula - C++17 Example: std::transform_exclusive_scan
// Compile: g++ -std=c++17 -Wall -Wextra -o example transform_exclusive_scan.cpp
// std::transform_exclusive_scan applies a unary transform to each element,
// then computes an exclusive prefix scan (each output excludes the current
// transformed element). It fuses transform + exclusive_scan in one pass.
#include <iostream>
#include <numeric>
#include <vector>
#include <functional>
#include <string>
int main() {
// --- Basic: square then exclusive scan ---
std::cout << "=== Square + exclusive scan ===" << std::endl;
std::vector<int> input = {1, 2, 3, 4, 5};
std::vector<int> result(input.size());
std::transform_exclusive_scan(
input.begin(), input.end(), result.begin(),
0, // initial value
std::plus<>{}, // binary op (accumulate)
[](int x) { return x * x; } // unary transform
);
std::cout << "Input: ";
for (int v : input) std::cout << v << " ";
std::cout << std::endl;
std::cout << "Squared: ";
for (int v : input) std::cout << (v * v) << " ";
std::cout << std::endl;
std::cout << "Exc. scan: ";
for (int v : result) std::cout << v << " ";
std::cout << std::endl;
// result[i] = init + sum of x*x for j < i
// [0, 1, 5, 14, 30]
// --- Double then exclusive scan with multiply ---
std::cout << "\n=== Double + multiply exclusive scan ===" << std::endl;
std::vector<int> vals = {1, 2, 3, 4};
std::vector<int> prod(vals.size());
std::transform_exclusive_scan(
vals.begin(), vals.end(), prod.begin(),
1, // identity for multiplication
std::multiplies<>{}, // binary op
[](int x) { return x * 2; } // double each element
);
std::cout << "Input: ";
for (int v : vals) std::cout << v << " ";
std::cout << std::endl;
std::cout << "Exc. scan: ";
for (int v : prod) std::cout << v << " ";
std::cout << std::endl;
// doubled: 2, 4, 6, 8
// exclusive product scan: [1, 2, 8, 48]
// --- String length prefix sums ---
std::cout << "\n=== String lengths exclusive scan ===" << std::endl;
std::vector<std::string> words = {"hi", "hello", "world", "!"};
std::vector<int> offsets(words.size());
std::transform_exclusive_scan(
words.begin(), words.end(), offsets.begin(),
0,
std::plus<>{},
[](const std::string& s) { return static_cast<int>(s.size()); }
);
std::cout << "Words: ";
for (const auto& w : words) std::cout << "\"" << w << "\" ";
std::cout << std::endl;
std::cout << "Offsets: ";
for (int v : offsets) std::cout << v << " ";
std::cout << std::endl;
// offsets: [0, 2, 7, 12] (start position of each word)
// --- With initial value ---
std::cout << "\n=== With initial value 100 ===" << std::endl;
std::vector<int> data = {1, 2, 3};
std::vector<int> out(data.size());
std::transform_exclusive_scan(
data.begin(), data.end(), out.begin(),
100, std::plus<>{}, [](int x) { return x; }
);
std::cout << "Result: ";
for (int v : out) std::cout << v << " ";
std::cout << std::endl;
// [100, 101, 103]
return 0;
}
/*
Expected output:
=== Square + exclusive scan ===
Input: 1 2 3 4 5
Squared: 1 4 9 16 25
Exc. scan: 0 1 5 14 30
=== Double + multiply exclusive scan ===
Input: 1 2 3 4
Exc. scan: 1 2 8 48
=== String lengths exclusive scan ===
Words: "hi" "hello" "world" "!"
Offsets: 0 2 7 12
=== With initial value 100 ===
Result: 100 101 103
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example transform_exclusive_scan.cpp