std::transform_reduce
定義於標頭檔案 <numeric> |
||
template< class InputIt1, class InputIt2, class T > T transform_reduce( InputIt1 first1, InputIt1 last1, |
(1) | (C++17 起) (C++20 起為 constexpr) |
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T > |
(2) | (C++17 起) |
template< class InputIt1, class InputIt2, class T, class BinaryOp1, class BinaryOp2 > |
(3) | (C++17 起) (C++20 起為 constexpr) |
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T, |
(4) | (C++17 起) |
template< class InputIt, class T, class BinaryOp, class UnaryOp > |
(5) | (C++17 起) (C++20 起為 constexpr) |
template< class ExecutionPolicy, class ForwardIt, class T, |
(6) | (C++17 起) |
std::plus<>(), std::multiplies<>()),實際上是預設 std::inner_product 的並行化版本。
[
first1,
last1)
和從 first2 開始的 std::distance(first1, last1) 個元素的範圍中的每對元素應用 transform,並與初始值 init 一起透過 reduce 歸約結果(可能以未指定的方式置換和聚合)。T
,則程式格式錯誤- reduce(init, init)
- reduce(init, transform(*first1, *first2))
- reduce(transform(*first1, *first2), init)
- reduce(transform(*first1, *first2), transform(*first1, *first2))
-
T
不是 可移動構造 (MoveConstructible) 的。 - transform 或 reduce 修改了
[
first1,
last1)
或[
first2,
last2)
的任何元素。 - transform 或 reduce 使
[
first1,
last1]
或[
first2,
last2]
的任何迭代器或子範圍失效。
[
first,
last)
中的每個元素應用 transform,並與初始值 init 一起透過 reduce 歸約結果(可能以未指定的方式置換和聚合)。T
,則程式格式錯誤- reduce(init, init)
- reduce(init, transform(*first))
- reduce(transform(*first), init)
- reduce(transform(*first), transform(*first))
-
T
不是 可移動構造 (MoveConstructible) 的。 - transform 或 reduce 修改了
[
first,
last)
的任何元素。 - transform 或 reduce 使
[
first,
last]
的任何迭代器或子範圍失效。
std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> 為 true。 |
(C++20 前) |
std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> 為 true。 |
(C++20 起) |
目錄 |
[edit] 引數
first1, last1 | - | 定義作為 transform 的左運算元的元素的範圍的迭代器對 |
first2 | - | 作為 transform 的右運算元的元素的範圍的開始 |
first, last | - | 定義作為 transform 的運算元的元素的範圍的迭代器對 |
init | - | 廣義和的初始值 |
policy | - | 要使用的 執行策略 |
reduce | - | 二元函式物件,將以未指定順序應用於 transform 的結果、其他 reduce 的結果和 init。 |
transform | - | 一元或二元函式物件,將應用於輸入範圍的每個元素。返回型別必須是 reduce 可接受的輸入。 |
型別要求 | ||
-InputIt1, InputIt2, InputIt 必須滿足 LegacyInputIterator 的要求。 | ||
-ForwardIt1, ForwardIt2, ForwardIt 必須滿足 LegacyForwardIterator 的要求。 |
[edit] 返回值
一組元素在二元操作 binary_op 下的廣義和定義如下
- 如果組中只有一個元素,則和就是該元素的值。
- 否則,按順序執行以下操作:
- 從組中取出任意兩個元素 elem1 和 elem2。
- 計算 binary_op(elem1, elem2) 並將結果放回組中。
- 重複步驟 1 和 2,直到組中只剩下一個元素。
[edit] 複雜度
給定 N 為 std::distance(first1, last1)(或 std::distance(first, last) 用於過載 (5,6))
[edit] 異常
帶有模板引數 ExecutionPolicy
的過載按如下方式報告錯誤
- 如果作為演算法一部分呼叫的函式執行丟擲異常,並且
ExecutionPolicy
是標準策略之一,則呼叫 std::terminate。對於任何其他ExecutionPolicy
,行為是實現定義的。 - 如果演算法未能分配記憶體,則丟擲 std::bad_alloc。
[edit] 注意
transform 從未應用於 init。
如果 first == last 或 first1 == last1,則返回未修改的 init。
[edit] 示例
transform_reduce
可用於並行化 std::inner_product。某些系統可能需要額外的支援才能獲得並行執行的優勢。例如,在 GNU/Linux 上,可能需要安裝 Intel TBB 並向 gcc/clang 編譯器提供 -ltbb 選項。
#if PARALLEL #include <execution> #define PAR std::execution::par, #else #define PAR #endif #include <algorithm> #include <functional> #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(PAR v.cbegin(), v.cend(), 0L, squared_sum); std::cout << "reduce(): " << sum2 << '\n'; auto sum3 = std::transform_reduce(PAR v.cbegin(), v.cend(), 0L, std::plus{}, [](auto val) { return val * val; }); std::cout << "transform_reduce(): " << sum3 << "\n\n"; } int main() { print_sum_squared(1); print_sum_squared(1'000); print_sum_squared(1'000'000); }
可能的輸出
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 // Compile-options for parallel execution on POSIX: // g++ -O2 -std=c++17 -Wall -Wextra -pedantic -DPARALLEL ./example.cpp -ltbb -o tr; ./tr
[edit] 另請參閱
對一個範圍的元素進行求和或摺疊 (函式模板) | |
對一個範圍的元素應用函式,並將結果儲存在目標範圍中 (函式模板) | |
(C++17) |
類似於 std::accumulate,但順序是亂序的 (函式模板) |