std::reduce
来自 cppreference.cn
定义于头文件 <numeric> |
||
template< class InputIt > typename std::iterator_traits<InputIt>::value_type |
(1) | (C++17 起) (C++20 起为 constexpr) |
template< class ExecutionPolicy, class ForwardIt > typename std::iterator_traits<ForwardIt>::value_type |
(2) | (C++17 起) |
template< class InputIt, class T > T reduce( InputIt first, InputIt last, T init ); |
(3) | (C++17 起) (C++20 起为 constexpr) |
template< class ExecutionPolicy, class ForwardIt, class T > T reduce( ExecutionPolicy&& policy, |
(4) | (C++17 起) |
template< class InputIt, class T, class BinaryOp > T reduce( InputIt first, InputIt last, T init, BinaryOp op ); |
(5) | (C++17 起) (C++20 起为 constexpr) |
template< class ExecutionPolicy, class ForwardIt, class T, class BinaryOp > |
(6) | (C++17 起) |
1) 等价于 reduce(first, last, typename std::iterator_traits<InputIt>::value_type{})。
3) 等价于 reduce(first, last, init, std::plus<>())。
5) 将范围
[
first,
last)
中的元素与初始值 init,通过 op 以未指定的方式进行置换和聚合,从而进行归约。2,4,6) 与 (1,3,5) 相同,但根据 policy 执行。
仅当满足所有以下条件时,这些重载才参与重载决议
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 起) |
给定 binary_op 作为实际的二元操作,
- 如果 binary_op 不满足结合律或交换律(例如浮点数加法),则结果是非确定性的。
- 如果以下任一值不能转换为 `T`,则程序是病态的:
- binary_op(init, *first)
- binary_op(*first, init)
- binary_op(init, init)
- binary_op(*first, *first)
- 如果满足以下任何条件,则行为是未定义的:
-
T
不是 可移动构造 (MoveConstructible) 的。 - binary_op 修改了
[
first,
last)
中的任何元素。 - binary_op 使
[
first,
last]
的任何迭代器或子范围失效。
-
目录 |
[编辑] 参数
first, last | - | 定义要应用算法的元素范围的迭代器对 |
init | - | 广义和的初始值 |
policy | - | 要使用的 执行策略 |
op | - | 二元 函数对象 (FunctionObject),将以未指定顺序应用于解引用输入迭代器的结果、其他 op 的结果和 init。 |
类型要求 | ||
-InputIt 必须满足 LegacyInputIterator 的要求。 | ||
-ForwardIt 必须满足 LegacyForwardIterator 的要求。 |
[编辑] 返回值
5,6) init 和
[
first,
last)
中元素在 op 上的广义和。一组元素在二元操作 binary_op 上的广义和定义如下:
- 如果组中只有一个元素,则和为该元素的值。
- 否则,按顺序执行以下操作:
- 从组中取出任意两个元素 elem1 和 elem2。
- 计算 binary_op(elem1, elem2) 并将结果放回组中。
- 重复步骤 1 和 2,直到组中只有一个元素。
[编辑] 复杂度
给定 N 为 std::distance(first, last)
5,6) O(N) 次 op 的应用。
[编辑] 异常
带有模板参数 ExecutionPolicy
的重载按如下方式报告错误
- 如果作为算法一部分调用的函数执行抛出异常,并且
ExecutionPolicy
是标准策略之一,则调用 std::terminate。对于任何其他ExecutionPolicy
,行为是实现定义的。 - 如果算法未能分配内存,则抛出 std::bad_alloc。
[编辑] 注意
std::reduce
的行为类似于 std::accumulate,但范围内的元素可以以任意顺序进行分组和重新排列。
[编辑] 示例
std::reduce
和 std::accumulate 的并排比较
运行此代码
#if PARALLEL #include <execution> #define SEQ std::execution::seq, #define PAR std::execution::par, #else #define SEQ #define PAR #endif #include <chrono> #include <iomanip> #include <iostream> #include <locale> #include <numeric> #include <utility> #include <vector> int main() { std::cout.imbue(std::locale("en_US.UTF-8")); std::cout << std::fixed << std::setprecision(1); auto eval = [](auto fun) { const auto t1 = std::chrono::high_resolution_clock::now(); const auto [name, result] = fun(); const auto t2 = std::chrono::high_resolution_clock::now(); const std::chrono::duration<double, std::milli> ms = t2 - t1; std::cout << std::setw(28) << std::left << name << "sum: " << result << '\t' << "time: " << ms.count() << " ms\n"; }; { const std::vector<double> v(100'000'007, 0.1); eval([&v]{ return std::pair{"std::accumulate (double)", std::accumulate(v.cbegin(), v.cend(), 0.0)}; }); eval([&v]{ return std::pair{"std::reduce (seq, double)", std::reduce(SEQ v.cbegin(), v.cend())}; }); eval([&v]{ return std::pair{"std::reduce (par, double)", std::reduce(PAR v.cbegin(), v.cend())}; }); } { const std::vector<long> v(100'000'007, 1); eval([&v]{ return std::pair{"std::accumulate (long)", std::accumulate(v.cbegin(), v.cend(), 0l)}; }); eval([&v]{ return std::pair{"std::reduce (seq, long)", std::reduce(SEQ v.cbegin(), v.cend())}; }); eval([&v]{ return std::pair{"std::reduce (par, long)", std::reduce(PAR v.cbegin(), v.cend())}; }); } }
可能的输出
// POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3; ./a.out std::accumulate (double) sum: 10,000,000.7 time: 356.9 ms std::reduce (seq, double) sum: 10,000,000.7 time: 140.1 ms std::reduce (par, double) sum: 10,000,000.7 time: 140.1 ms std::accumulate (long) sum: 100,000,007 time: 46.0 ms std::reduce (seq, long) sum: 100,000,007 time: 67.3 ms std::reduce (par, long) sum: 100,000,007 time: 63.3 ms // POSIX: g++ -std=c++23 ./example.cpp -ltbb -O3 -DPARALLEL; ./a.out std::accumulate (double) sum: 10,000,000.7 time: 353.4 ms std::reduce (seq, double) sum: 10,000,000.7 time: 140.7 ms std::reduce (par, double) sum: 10,000,000.7 time: 24.7 ms std::accumulate (long) sum: 100,000,007 time: 42.4 ms std::reduce (seq, long) sum: 100,000,007 time: 52.0 ms std::reduce (par, long) sum: 100,000,007 time: 23.1 ms
[编辑] 另请参阅
对一个范围的元素进行求和或折叠 (函数模板) | |
对一个范围的元素应用函数,并将结果存储在目标范围中 (函数模板) | |
(C++17) |
应用一个可调用对象,然后进行乱序归约 (函数模板) |
(C++23) |
对一个范围的元素进行左折叠 (算法函数对象) |