zoukankan      html  css  js  c++  java
  • 【c++】c++中的for_each和accumulate函数

    for_each函数

    for_each函数定义在<algorithm>头文件中,其函数声明为:

    template<class InputIt, class UnaryFunction>
    constexpr UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
    {
        for (; first != last; ++first) {
            f(*first);
        }
        return f; // implicit move since C++11
    }
    

    接收两个迭代器first,last,并对[first,last)范围内的元素遍历,传递给函数或函数对象f,遍历结束返回函数或函数对象f

    f可以是一个函数,一个函数对象,或者是一个lambda表达式

    用函数作为谓词

    void print(const int &a) {
        cout << a << " ";
    }
    
    int main() {
        std::vector<int> nums{3, 4, 2, 8, 15, 267};
        // for_each函数遍历完之后,会把谓词返回
        void (*pfunc)(const int &) = for_each(nums.begin(), nums.end(), print);
        cout << endl;
        pfunc(6);
    }
    

    用函数对象作为谓词

    只要是重载了()运算符的类或者结构体,就是函数对象类,该类的实例即为函数对象。

    结构体中成员属性和成员方法默认为public

    类中成员属性和成员方法默认为private

    struct Sum {
        Sum() : sum{0} {}
    
        // 重载()运算符
        void operator()(int n) { sum += n; }
    
        int sum;
    };
    
    
    std::vector<int> nums{3, 4, 2, 8, 15, 267};
    //将容器中的元素遍历分别传递给函数对象进行累加,遍历结束返回该函数对象
    Sum s = std::for_each(nums.begin(), nums.end(), Sum());
    //从函数对象中获取累加结果
    std::cout << "sum: " << s.sum << '\n';
    

    用lambda表达式作为谓词

    std::vector<int> nums{3, 4, 2, 8, 15, 267};
    void (*pfunc)(const int &) = for_each(nums.begin(), nums.end(), [](const int &n) { 																	cout << n << " "; });
    cout << endl;
    pfunc(7);
    

    accumulate函数

    accumulate函数定义在numeric头文件中,其函数定义有两种:

    第一种实现就是累加[first,last)范围内的元素,init+=*first并返回累加结果

    template<class InputIt, class T>
    T accumulate(InputIt first, InputIt last, T init)
    {
        for (; first != last; ++first) {
            init = std::move(init) + *first; // std::move since C++20
        }
        return init;
    }
    

    第二种实现累加规则不一样了,累加规则可以在谓词里面定义,init = op(std::move(init), *first) 并返回累加结果

    template<class InputIt, class T, class BinaryOperation>
    T accumulate(InputIt first, InputIt last, T init, 
                 BinaryOperation op)
    {
        for (; first != last; ++first) {
            init = op(std::move(init), *first); // std::move since C++20
        }
        return init;
    }
    

    用函数作为谓词

    // 注意lhs和rhs的顺序!!!
    int op_sum(int total, int value) {
        return total + value * value;
    }
    
    vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
    // 使用默认累加
    cout << accumulate(v.begin(), v.end(), 0) << endl;
    // 使用函数作为谓词,计算平方和
    cout << accumulate(v.begin(), v.end(), 0, op_sum) << endl;
    

    用函数对象作为谓词

    template<typename T>
    class OpSum {
    private:
        int power;
    public:
        explicit OpSum(int p) : power(p) {}
    
        T operator()(const T &total, const T &value) {  //计算 value的power次方,加到total上
            return total + pow(value, power);
        }
    };
    
    
    vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
    // 使用默认累加
    cout << accumulate(v.begin(), v.end(), 0) << endl;
    // 使用函数对象作为谓词,计算平方和
    cout << accumulate(v.begin(), v.end(), 0, OpSum<int>(2)) << endl;
    

    用lambda表达式作为谓词

    vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
    // 使用默认累加
    cout << accumulate(v.begin(), v.end(), 0) << endl;
    
    // 使用lambda作为谓词,计算平方和
    cout << accumulate(v.begin(), v.end(), 0, [](const int &total, const int &value) { return total + value * value; })
        << endl;
    

    对于一些简单的需求,我们可以用默认累加或者lambda表达式一行搞定,当然,如果需要更加复杂的需求,比如累加规则多样,甚至想对不同的数据类型累加规则,那么推荐使用函数对象。

    全部代码如下:

    //函数对象
    #include <iostream>
    #include <vector>
    #include <numeric> //accumulate 在此头文件定义
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    // 注意lhs和rhs的顺序!!!
    int op_sum(int total, int value) {
        return total + value * value;
    }
    
    template<typename T>
    class OpSum {
    private:
        int power;
    public:
        explicit OpSum(int p) : power(p) {}
    
        T operator()(const T &total, const T &value) {  //计算 value的power次方,加到total上
            return total + pow(value, power);
        }
    };
    
    int main() {
        vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
        // 使用默认累加
        cout << accumulate(v.begin(), v.end(), 0) << endl;
        // 使用函数作为谓词,计算平方和
        cout << accumulate(v.begin(), v.end(), 0, op_sum) << endl;
        // 使用函数对象作为谓词,计算平方和
        cout << accumulate(v.begin(), v.end(), 0, OpSum<int>(2)) << endl;
        // 使用lambda作为谓词,计算平方和
        cout << accumulate(v.begin(), v.end(), 0, [](const int &total, const int &value) { return total + value * value; })
             << endl;
        return 0;
    }
    

    对比

    for_each accumulate
    谓词 仅需一个参数,对参数的处理不需要和[first,last)范围内的其它元素有关联 需要两个参数(init,value),对范围内的元素处理有关联
    返回结果 将谓词返回,谓词中可以存放处理的结果 将累加结果返回
    总结 对范围内的元素进行某种变换调整 常用于累加计算范围内的元素的映射
  • 相关阅读:
    线程应用示例
    Microsoft Visual Studio 2005 BETA2最新资源大杂烩
    135,139,445端口的关闭方法
    开源软件新时代 55个经典开源Windows工具
    图书商城项目总论
    无处不在的XML
    ADO.NET实例教学一
    递归
    手写代码生成器
    数据库的应用详解三
  • 原文地址:https://www.cnblogs.com/ericling/p/15641345.html
Copyright © 2011-2022 走看看