【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),對範圍內的元素處理有關聯
返回結果 將謂詞返回,謂詞中可以存放處理的結果 將累加結果返回
總結 對範圍內的元素進行某種變換調整 常用於累加計算範圍內的元素的映射
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章