c++当中关于reduce accumulate函数的一些延申思考

 reduce() 和 accumulate() 都是用于对集合(比如数组)中元素进行归约操作:

accumulate用于对迭代器指示范围[first, last)中元素进行累加操作,对于序列当中的每个元素,一次应用某个二元操作(默认加法),并且将结果累加到一个初始值上。函数原型如下:

template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init);

template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init, BinaryOperation op);

用法的示例:

#include <iostream>
#include <numeric>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 使用默认的加法操作
    int sum = std::accumulate(v.begin(), v.end(), 0);
    std::cout << "Sum: " << sum << std::endl;  // 输出: Sum: 15

    // 使用乘法操作
    int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
    std::cout << "Product: " << product << std::endl;  // 输出: Product: 120

    return 0;
}

reduce 同样是对迭代器指示范围内元素进行归约操作,但支持并行执行,操作元素必须是无关联的。函数原型:

template<class InputIt>
typename std::iterator_traits<InputIt>::value_type
reduce(InputIt first, InputIt last);

template<class InputIt, class T>
T reduce(InputIt first, InputIt last, T init);

template<class InputIt, class T, class BinaryOperation>
T reduce(InputIt first, InputIt last, T init, BinaryOperation binary_op);

template<class ExecutionPolicy, class ForwardIt>
typename std::iterator_traits<ForwardIt>::value_type
reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last);

template<class ExecutionPolicy, class ForwardIt, class T>
T reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, T init);

template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOperation>
T reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, T init, BinaryOperation binary_op);

使用的例子:

#include <iostream>
#include <numeric>
#include <vector>
#include <execution>  // 需要包含以使用并行执行策略

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 使用默认的加法操作
    int sum = std::reduce(v.begin(), v.end());
    std::cout << "Sum: " << sum << std::endl;  // 输出: Sum: 15

    // 使用乘法操作
    int product = std::reduce(v.begin(), v.end(), 1, std::multiplies<int>());
    std::cout << "Product: " << product << std::endl;  // 输出: Product: 120

    // 使用并行执行策略
    int parallel_sum = std::reduce(std::execution::par, v.begin(), v.end());
    std::cout << "Parallel Sum: " << parallel_sum << std::endl;  // 输出: Parallel Sum: 15

    return 0;
}

上述函数在使用的时候,如果需要指示运算的类型,则需要输入函数对象,比如:

std::multiplies<int>()
std::plus<int>()
std::minus<int>()
std::divides<int>()

那么为什么需要这么写呢?

在reduce accumulate 函数当中为什么不能直接写multiplies<int>,非得multiplies<int>()?

因为前者是函数类型(模板类),后者是函数对象(临时对象,类的实例化)。

模板类 multiplies<int> 是一个类型,它定义了如何执行乘法操作。要使用这个操作,我们需要一个具体的实例——一个对象。multiplies<int>() 就是创造了这样一个对象。reduce accumulate期望接收一个可调用对象(即函数对象、普通函数或 lambda 表达式)作为参数。类本身不能作为可调用对象传递,必须传递一个实例化的对象。

可以简单理解为reduce accumulate需要一个能够直接调用的对象,要么是类的实例要么是函数。常用的一些函数同样如此,比如sort当中,常用的写法是匿名函数:

ranges::sort(nums, [](int a, int b){
    return a > b;
});

下面是一些辅助知识:

函数对象是可以像函数一样调用的对象。可通过重载 operator() 运算符来实现这一功能。如 accumulatereduce,都可以接受函数对象作为参数,以指定用于归约操作的二元运算:

struct Multiply {
    int operator()(int a, int b) const {
        return a * b;
    }
};

Multiply multiply;
int result = multiply(3, 4);  // 等价于 3 * 4

在底层实现上,std::multiplies<int> 是一个模板类的实例化,重载了 operator() 运算符,使得实例对象可以像函数一样调用。这种设计使得标准库函数能够接受函数对象作为参数:

namespace std {
    template<typename T>
    struct multiplies {
        T operator()(const T& lhs, const T& rhs) const {
            return lhs * rhs;
        }
    };
}

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值