STL演算法之非修改式序列演算法
阿新 • • 發佈:2020-12-28
1、for_each() 遍歷容器
在實現遍歷的基礎上,利用引數三(仿函式)實現其他操作,僅遍歷列印,或者遍歷更改容器值。
【原型】
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function fn); 引數一:迭代器 引數二:迭代器 引數三:仿函式(也可以叫 函式物件)
#include <iostream> #include <algorithm> // std::for_each #include <vector> void myfunction(int i) { // function: 僅遍歷列印容器內的值 std::cout << ' ' << i; } struct myclass { // function object type: void operator() (int i) //僅遍歷列印容器內的值 { std::cout << ' ' << i; } } myobject; int main() { std::vector<int> myvector; myvector.push_back(10); myvector.push_back(20); myvector.push_back(30); std::cout << "myvector contains:"; for_each(myvector.begin(), myvector.end(), myfunction); std::cout << '\n'; // or std::cout << "myvector contains:"; for_each(myvector.begin(), myvector.end(), myobject); std::cout << '\n'; return 0; }
對於引數3 函式如何呼叫的問題,我疑惑了很久,今天百度了很長時間,然後想起來看原始碼,忽然就有點明白了。
for_each()原始碼 // FUNCTION TEMPLATE for_each template <class _InIt, class _Fn> _Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) // perform function for each element [_First, _Last) { _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); // 獲取 first 迭代器指向的地址 const auto _ULast = _Get_unwrapped(_Last); // 獲取 Last 迭代器指向的地址 for (; _UFirst != _ULast; ++_UFirst) // 放入一個for 迴圈,遍歷容器中所有值的地址 { _Func(*_UFirst); // * _UFirst 拿出此地址的值,作為引數,傳遞到引數3 中 } return _Func; //返回函式物件的最終狀態 }
以下示例來自使用者文章:C++for_each()的返回值,使用for_each的返回值,獲取1-100的總和,
#include <iostream> #include <vector> #include <algorithm> using namespace std; /* for_each()它可以返回其仿函式(返回所傳入的函式物件的最終狀態). 這樣我們就可以通過for_each()的返回值來獲取仿函式的狀態. */ class CSum { public: CSum(){ m_sum = 0; } void operator()(int n)/* 仿函式 */{ m_sum += n; } int GetSum() const{ return m_sum; } private: int m_sum; }; int main() { vector<int> vi; for (int i = 1; i <= 100; i++) { vi.push_back(i); } //通過for_each返回值訪問其最終狀態(返回所傳入的函式物件的最終狀態). CSum cs = for_each(vi.begin(), vi.end(), CSum());//最後一個引數相當於用CSum建立了一個無參物件 cout << cs.GetSum() << endl; return 0; }
在for_each()的基礎之上,通過仿函式類,使容器內的元素 * 2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template <class T>
void FillValue(T& vect, int first, int last){ // 初始化容器
if (last >= first){
for (int i = first; i <= last; ++i)
vect.insert(vect.end(), i);
}
}
void print(int elem){ // 函式物件
cout << elem << " ";
}
template <class T>
class Multiple { // 仿函式類,
private:
T theValue;
public:
Multiple(const T& v) : theValue(v)
{
}
void operator()(T& elem) const // 過載 (),使類具有類似函式的行為,就是仿函式類
{
elem *= theValue; // * theValue
}
};
void main()
{
vector <int> myvector;
FillValue(myvector, 1, 10); // 給容器賦值 1-10
for_each(myvector.begin(), myvector.end(), print); // 僅遍歷 列印
cout << endl;
for_each(myvector.begin(), myvector.end(), Multiple<int>(2)); //遍歷 更改 容器值
for_each(myvector.begin(), myvector.end(), print);
cout << endl;
}
對以上示例中的class Multiple 仿函式類(該名詞出現在《C++STL標準程式庫設計指南》),作者的解釋是:在類中實現函式operator(),之後這個類就有了類似函式的行為,就是一個仿函式類。
仿函式:《C++標準程式庫》的解釋是:仿函式是泛型程式設計強大威力和純粹抽象概念的又一例證。可以說,任何東西,只有其行為像函式,他就是一個函式,因此如果你定義了一個物件,行為像函式,它就可以當做函式來使用。
那麼什麼才算具備函式行為呢?所謂函式行為,是指可以使用圓括號傳遞引數,藉以呼叫某個東西。過載()即可。