1. 程式人生 > 其它 >STL演算法之非修改式序列演算法

STL演算法之非修改式序列演算法

技術標籤:C++c++stl

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++標準程式庫》的解釋是:仿函式是泛型程式設計強大威力和純粹抽象概念的又一例證。可以說,任何東西,只有其行為像函式,他就是一個函式,因此如果你定義了一個物件,行為像函式,它就可以當做函式來使用。

那麼什麼才算具備函式行為呢?所謂函式行為,是指可以使用圓括號傳遞引數,藉以呼叫某個東西。過載()即可。