std::reduce
来自 cppreference.com
在头文件 <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
不是 可移动构造. - binary_op 修改了
[
first,
last)
中的任何元素。 - binary_op 使
[
first,
last]
中的任何迭代器或子范围失效。
-
内容 |
[编辑] 参数
first, last | - | 要应用算法的元素范围 |
init | - | 广义和的初始值 |
policy | - | 要使用的执行策略。有关详细信息,请参阅 执行策略。 |
op | - | 二元 函数对象,它将以未指定顺序应用于取消引用输入迭代器的结果、其他 op 和 init 的结果。 |
类型要求 | ||
-InputIt 必须满足 传统输入迭代器 的要求。 | ||
-ForwardIt 必须满足 传统前向迭代器 的要求。 |
[编辑] 返回值
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 <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) |
将元素范围左折叠 (niebloid) |