for_each function
for_each function is defined in the < algorithm > header file, and its function declaration is:
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 }
Receive two iterators, first and last, traverse the elements within the range of [first, last], pass them to the function or function object F, and return the function or function object f after traversal
f can be a function, a function object, or a lambda expression
Using functions as predicates
void print(const int &a) { cout << a << " "; } int main() { std::vector<int> nums{3, 4, 2, 8, 15, 267}; // After traversing the for_each function, the predicate will be returned void (*pfunc)(const int &) = for_each(nums.begin(), nums.end(), print); cout << endl; pfunc(6); }
Using function objects as predicates
As long as it is a class or structure that overloads the () operator, it is a function object class, and the instance of this class is a function object.
The member attribute and member method in the structure are public by default
The member properties and methods in the class are private by default
struct Sum { Sum() : sum{0} {} // Overload () operator void operator()(int n) { sum += n; } int sum; }; std::vector<int> nums{3, 4, 2, 8, 15, 267}; //Pass the element traversal in the container to the function object respectively for accumulation, and return the function object after traversal Sum s = std::for_each(nums.begin(), nums.end(), Sum()); //Get accumulation result from function object std::cout << "sum: " << s.sum << '\n';
Using lambda expressions as predicates
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);
Calculate function
The aggregate function is defined in the numeric header file. There are two types of function definitions:
The first implementation is to accumulate the elements in the range of [first, last], init+=*first, and return the accumulation result
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; }
The second implementation is different from the accumulation rule. The accumulation rule can be defined in the predicate, init = op(std::move(init), *first) and return the accumulation result
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; }
Using functions as predicates
// Pay attention to the order of lhs and 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 << " "; }); // Use default accumulation cout << accumulate(v.begin(), v.end(), 0) << endl; // Use functions as predicates to calculate the sum of squares cout << accumulate(v.begin(), v.end(), 0, op_sum) << endl;
Using function objects as predicates
template<typename T> class OpSum { private: int power; public: explicit OpSum(int p) : power(p) {} T operator()(const T &total, const T &value) { //Calculate the power of value and add it to 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 << " "; }); // Use default accumulation cout << accumulate(v.begin(), v.end(), 0) << endl; // Use the function object as the predicate to calculate the sum of squares cout << accumulate(v.begin(), v.end(), 0, OpSum<int>(2)) << endl;
Using lambda expressions as predicates
vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; }); // Use default accumulation cout << accumulate(v.begin(), v.end(), 0) << endl; // Use lambda as the predicate to calculate the sum of squares cout << accumulate(v.begin(), v.end(), 0, [](const int &total, const int &value) { return total + value * value; }) << endl;
For some simple requirements, we can use the default accumulation or lambda expression to solve them in one line. Of course, if more complex requirements are needed, such as various accumulation rules, and even want to accumulate rules for different data types, it is recommended to use function objects.
All codes are as follows:
//Function object #include <iostream> #include <vector> #Include < numeric > / / accumulate is defined in this header file #include <algorithm> #include <cmath> using namespace std; // Pay attention to the order of lhs and 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) { //Calculate the power of value and add it to 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 << " "; }); // Use default accumulation cout << accumulate(v.begin(), v.end(), 0) << endl; // Use functions as predicates to calculate the sum of squares cout << accumulate(v.begin(), v.end(), 0, op_sum) << endl; // Use the function object as the predicate to calculate the sum of squares cout << accumulate(v.begin(), v.end(), 0, OpSum<int>(2)) << endl; // Use lambda as the predicate to calculate the sum of squares cout << accumulate(v.begin(), v.end(), 0, [](const int &total, const int &value) { return total + value * value; }) << endl; return 0; }
contrast
for_each | accumulate | |
---|---|---|
predicate | Only one parameter is required, and the processing of parameters does not need to be associated with other elements in the [first, last] range | Two parameters (init,value) are required to be associated with the processing of elements in the range |
Return results | Returns the predicate, in which the processing results can be stored | Return the accumulation result |
summary | Make some transformation adjustment to the elements in the range | It is often used to accumulate the mapping of elements within the calculation range |