# std::transform_reduce

< cpp‎ | algorithm

定义于头文件 `<numeric>` |  |
| (1) |
template<class InputIt1, class InputIt2, class T> T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init); |  | (C++17 起) (C++20 前)
template<class InputIt1, class InputIt2, class T> constexpr T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init); |  | (C++20 起)
| (2) |
template <class InputIt1, class InputIt2, class T, class BinaryOp1, class BinaryOp2> T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOp1 binary_op1, BinaryOp2 binary_op2); |  | (C++17 起) (C++20 前)
template <class InputIt1, class InputIt2, class T, class BinaryOp1, class BinaryOp2> constexpr T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOp1 binary_op1, BinaryOp2 binary_op2); |  | (C++20 起)
| (3) |
template<class InputIt, class T, class BinaryOp, class UnaryOp> T transform_reduce(InputIt first, InputIt last, T init, BinaryOp binop, UnaryOp unary_op); |  | (C++17 起) (C++20 前)
template<class InputIt, class T, class BinaryOp, class UnaryOp> constexpr T transform_reduce(InputIt first, InputIt last, T init, BinaryOp binop, UnaryOp unary_op); |  | (C++20 起)
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T> T transform_reduce(ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, T init); | (4) | (C++17 起)
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 binary_op1, BinaryOp2 binary_op2); | (5) | (C++17 起)
template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOp, class UnaryOp> T transform_reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, T init, BinaryOp binary_op, UnaryOp unary_op); | (6) | (C++17 起)

1) 等价于 `transform_reduce(first1, last1, first2, init, std::plus<>(), std::multiplies<>());` ，默认的 std::inner_product 的等效并行版本
2) 应用 `binary_op2` 到来自范围 [first; last) 和始于 first2 的范围的每对元素，并在 `binary_op1` 上与初始值 `init` 一同规约结果（可以以未指定行为重排聚合）
3) 应用 `unary_op` 到范围 [first; last) 中的每个元素，并在 `binary_op` 上与初始值 `init` 一同规约结果（可以以未指定行为重排聚合）。
4-6) 同 (1-3) ，但按照 `policy` 执行。这些重载仅若 std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> (C++20 前)std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

若 `binary_op`/`binary_op2` 为非交换或非结合则行为不确定。

若 `unary_op` 、 `binary_op` 、 `binary_op1` 或 `binary_op2` 修改输入范围中的任何元素或非法化范围中的任何迭代器，含尾迭代器，则行为未定义。

### 参数

first, last | - | 要应用算法的元素范围
init | - | 广义和的初始值
policy | - | 使用的执行策略，细节见执行策略。
unary_op | - | 将应用于输入范围的每个元素的一元函数对象 (FunctionObject) 。返回类型必须可为 `binary_op` 的输入所接受
binary_op | - | 将以未指定顺序应用于 `unary_op` 的结果、其他 `binary_op` 的结果和 `init` 的二元函数对象 (FunctionObject) 。
类型要求
- 为使用重载 (3,6) ， `T` 必须满足可移动构造 (MoveConstructible) 的要求。且表达式 binary_op(init, unary_op(*first)) 、 binary_op(unary_op(*first), init) 、 binary_op(init, init) 和 binary_op(unary_op(*first), unary_op(*first)) 的结果必须可转换为 T
- 为使用重载 (2,5) ， `T` 必须满足可移动构造 (MoveConstructible) 的要求。且表达式 binary_op1(init, binary_op2(*first1, *first2)) 、 binary_op1(binary_op2(*first1, *first2), init) 、 binary_op1(init, init) 和 binary_op1(binary_op2(*first1, *first2), binary_op2(*first1, *first2)) 的结果必须可转换为 T
- `InputIt` 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- `ForwardIt` 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

### 返回值

2) `init` 和 `binary_op2(*first,*first2)` 、 `binary_op2(*(first+1),*(first2+1))` ……在 `binary_op1` 上的广义和
3) `init` 和 `unary_op(*first)` 、 `unary_op(*(first+1))` …… `unary_op(*(last-1))` 在 `binary_op` 上的广义和，

其中广义和 GSUM(op, a
1, ..., a
N) 定义如下：

- 若 N=1 ，则为 a
  1
- 若 N > 1 ，则为 op(GSUM(op, b
  1, ..., b
  K), GSUM(op, b
  M, ..., b
  N)) ，其中

  - b
    1, ..., b
    N 可以是 a1, ..., aN 的任意重排，若
  - 1 < K+1 = M ≤ N

换言之， unary_op 或 binary_op1 的结果能以任意顺序组合排列。

### 复杂度

1,2,4,5) 各使用 O(last1 - first1) 次 `binary_op1` 和 `binary_op2` 。
3,6) 各使用 O(last - first) 次 `unary_op` 和 `binary_op` 。

### 异常

拥有名为 `ExecutionPolicy` 的模板形参的重载按下列方式报告错误：

- 若作为算法一部分调用的函数的执行抛出异常，且 `ExecutionPolicy` 为标准策略之一，则调用 std::terminate 。对于任何其他 `ExecutionPolicy` ，行为是实现定义的。
- 若算法无法分配内存，则抛出 std::bad_alloc 。

### 注解

在一元-二元重载 (3,6) 中， `unary_op` 不应用到 `init`

若 `first == last` 或 `first1 == last1` ，则返回不修改的 `init`

### 示例

transform_reduce 能用于并行化的 std::inner_product ：

    #include <vector>
    #include <functional>
    #include <iostream>
    #include <numeric>
    #include <execution>

    int main()
    {
        std::vector<double> xvalues(10007, 1.0), yvalues(10007, 1.0);

        double result = std::transform_reduce(
            std::execution::par,
            xvalues.begin(), xvalues.end(),
            yvalues.begin(), 0.0
        );
        std::cout << result << '\n';
    }

输出：

    10007

### 参阅

accumulate | 对一个范围内的元素求和 (函数模板)
transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)
reduce (C++17) | 类似 std::accumulate，但不依序执行 (函数模板)