std::transform_reduce
| 定义于头文件 <numeric>
|
||
template< class InputIt1, class InputIt2, class T >
T transform_reduce( InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init );
|
(1) | (自 C++17 起) (自 C++20 起 constexpr) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class T >
T transform_reduce( ExecutionPolicy&& policy,
ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, T init );
|
(2) | (自 C++17 起) |
template< class InputIt1, class InputIt2, class T,
class BinaryOp1, class BinaryOp2 >
T transform_reduce( InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init,
BinaryOp1 reduce, BinaryOp2 transform );
|
(3) | (自 C++17 起) (自 C++20 起 constexpr) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class T,
class BinaryOp1, class BinaryOp2 >
T transform_reduce( ExecutionPolicy&& policy,
ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, T init,
BinaryOp1 reduce, BinaryOp2 transform );
|
(4) | (自 C++17 起) |
template< class InputIt, class T,
class BinaryOp, class UnaryOp >
T transform_reduce( InputIt first, InputIt last, T init,
BinaryOp reduce, UnaryOp transform );
|
(5) | (自 C++17 起) (自 C++20 起 constexpr) |
template< class ExecutionPolicy,
class ForwardIt, class T,
class BinaryOp, class UnaryOp >
T transform_reduce( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, T init,
BinaryOp reduce, UnaryOp transform );
|
(6) | (自 C++17 起) |
transform_reduce(first1, last1, first2, init,
std::plus<>(), std::multiplies<>())
transform 中的每对元素以及从 [first1, last1) 开始的 std::distance(first1, last1) 个元素应用 first2,并通过 init 将结果(可能以未指定的方式排列和聚合)连同初始值 reduce 归约。reduce 不是结合性的或不是交换性的(例如浮点加法),则结果不确定。T,则程序非良构:
reduce(init, init)reduce(init, transform(*first1, *first2))reduce(transform(*first1, *first2), init)reduce(transform(*first1, *first2), transform(*first1, *first2))
last2 作为 std::distance(first1, last1) 的第 个后继迭代器,如果满足以下任一条件,则行为未定义:
first2 如果 T不是 MoveConstructible,或transform或reduce修改[first1,last1)或[first2,last2)的任何元素,transform或reduce使[first1,last1]或[first2,last2]的任何迭代器或子范围失效。
transform 中的每个元素应用 [first, last),并通过 init 将结果(可能以未指定的方式排列和聚合)连同初始值 reduce 归约。reduce 不是结合性的或不是交换性的(例如浮点加法),则结果不确定。T,则程序非良构:
reduce(init, init)reduce(init, transform(*first))reduce(transform(*first), init)reduce(transform(*first), transform(*first))
T如果 不是 MoveConstructibletransform,或reduce修改[first,last)的任何元素,transform或reduce使[first,last]的任何迭代器或子范围失效。
policy 执行。true 时才参与重载决议:|
|
(至 C++20) |
|
|
(自 C++20 起) |
参数
| first1, last1 | - | 定义作为 transform 左操作数的元素范围的迭代器对 |
| first2 | - | 作为 transform 右操作数的元素范围的起始位置 |
| first, last | - | 定义作为 transform 操作数的元素范围的迭代器对 |
| init | - | 广义求和的初始值 |
| policy | - | 要使用的 执行策略 |
| reduce | - | 将以未指定顺序应用于 transform 结果、其他 reduce 结果和 init 的二元 函数对象 |
| transform | - | 将应用于输入范围每个元素的一元或二元 函数对象 。其返回类型必须可作为 reduce 的输入 |
| 类型要求 | ||
-
InputIt1, InputIt2, InputIt
必须满足
LegacyInputIterator
的要求
|
||
-
ForwardIt1, ForwardIt2, ForwardIt
必须满足
LegacyForwardIterator
的要求
|
||
返回值
一组元素在二元运算 binary_op 上的 广义和 定义如下:
- 如果该组仅有一个元素,则总和即为该元素的值。
- 否则,按顺序执行以下操作:
- 从群组中取出任意两个元素 elem1 和 elem2 。
- 计算 binary_op ( elem1, elem2 ) 并将结果放回群组。
- 重复步骤1和2,直到群组中仅剩一个元素。
复杂度
给定 N 为 std:: distance ( first1, last1 ) (对于重载 (5,6) 则为 std:: distance ( first, last ) ):
异常
带有名为
ExecutionPolicy
模板参数的重载按如下方式报告错误:
-
如果作为算法一部分调用的函数执行抛出异常,且
ExecutionPolicy是某个 标准策略 ,则调用 std::terminate 。对于其他任何ExecutionPolicy,其行为由实现定义。 - 如果算法无法分配内存,则抛出 std::bad_alloc 。
注释
transform 永远不会应用于 init 。
若 first == last 或 first1 == last1 ,则返回未经修改的 init 。
示例
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 // 在 POSIX 系统上并行执行的编译选项: // g++ -O2 -std=c++17 -Wall -Wextra -pedantic -DPARALLEL ./example.cpp -ltbb -o tr; ./tr
另见
| 对范围内的元素求和或折叠 (函数模板) | |
| 将函数应用于范围内的元素,并将结果存储到目标范围 (函数模板 & 算法函数对象) | |
(C++20) |
|
(C++17) |
类似于 std::accumulate,但无序 (函数模板) |