1. 程式人生 > >STL函數適配器

STL函數適配器

成員 begin void operator 綁定 定義 img 計算 轉換

一:適配器簡介

C++中有三類適配器,分別是容器適配器叠代器適配器函數適配器,這裏主要介紹函數適配器

(一)函數適配器簡介

STL中已經定義了大量的函數對象,但是有時候需要對函數返回值進行進一步的簡單計算,或者填上多余的參數,
才可以帶入其他的算法中進行下一步數據處理,不能直接帶入算法。
函數適配器就實現了這一功能:將一種函數對象轉化為另外一種符合要求的函數對象
函數適配器可以分為4大類:
綁定適配器(bind adaptor),
組合適配器(composite adaptor),
指針函數適配器(pointer adaptor),
成員函數適配器(member function adaptor)

(二)綁定適配器(bind adaptor)

技術分享圖片

(三)組合適配器(composite adaptor)

技術分享圖片

(四) 指針函數適配器(pointer adaptor)

技術分享圖片

(五)成員函數適配器(member function adaptor)

技術分享圖片

二:函數適配器輔助函數

直接構造STL中的函數適配器通常會導致冗長的類型聲明。---->之前說過模板函數和STL中類型是嚴格定義的,需要我們顯式寫出
為了簡化函數適配器的構造,
STL還提供了函數適配器輔助函數,借助於泛型自動推斷技術,無需顯式的類型聲明便可以實現函數適配器的構造。

技術分享圖片

三:常用函數適配器

標準庫提供一組函數適配器,用來特殊化或者擴展一元和二元函數對象。

(一)綁定器(binder): 將二元函數對象轉一元函數對象

binder通過把二元函數對象的一個實參綁定到一個特殊的值上,將其轉換成一元函數對象。
C++標準庫提供兩種預定義的binder適配器(適配器輔助函數)
bind1st和bind2nd,前者把值綁定到二元函數對象的第一個實參上,後者綁定在第二個實參上

(二)取反器(negator) : 操作謂詞函數

negator是一個將函數對象的值翻轉的函數適配器
標準庫提供兩個預定義的ngeator適配器(適配器輔助函數)
not1翻轉一元預定義函數對象的真值,而not2翻轉二元謂詞函數的真值。

(三)常用函數適配器案例:《重點》

1.使用綁定器和預定義函數對象

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>    //由於要使用到預定義函數對象,所以引入

using namespace std;

template<typename T>
void ShowEle(const T& t)    //用於打印容器數據
{
    cout << t << " ";
}
int main()
{
    vector<int> v1, v2, v3;

    for (int i = 0; i < 10;i++)
        v1.push_back(rand() % 30);    //v1數據插入

    //打印數據
    for_each(v1.begin(), v1.end(), ShowEle<int>);
    cout << endl;

    int num = count_if(v1.begin(), v1.end(), bind2nd(greater<int>(), 2));
    cout << num << endl;

    system("pause");
    return 0;
}

補充:count和count_if

)count(first,last,value):first是容器的首叠代器,last是容器的末叠代器,value是詢問的元素,整個函數返回int型。count函數的功能是:統計容器中等於value元素的個數。

)count_if(first,last,comp) (在comp為true的情況下計數) 或者 count_if(first,last,value,comp) (這個是在comp為true的情況下統計容器中等於value的元素):first為首叠代器,last為末叠代器,value為要查詢的元素,comp為比較bool函數,為true則計數,函數返回型是int。

註:此兩個函數復雜度是線性的,適用於小規模運算。count_if更加靈活

2.使用自定義謂詞和綁定器《重點》

template<typename T>
void ShowEle(const T& t)    //用於打印容器數據
{
    cout << t << " ";
}

template<typename T>
class Mygreater :public binary_function<T, T, bool>  //1.自定義謂詞需要繼承binary_function
{
public:
    bool operator() (const T& iLeft, const T& iRight) const  //2.重載()函數需要加上const,變為常函數
    {
        return (iLeft > iRight);//如果是實現less<int>的話,這邊是寫return (iLeft<iRight);
    }
};

int main()
{
    vector<int> v1, v2, v3;

    for (int i = 0; i < 10;i++)
        v1.push_back(rand() % 30);    //v1數據插入

    //打印數據
    for_each(v1.begin(), v1.end(), ShowEle<int>);
    cout << endl;

    int num = count_if(v1.begin(), v1.end(), bind2nd(Mygreater<int>(), 2));
    cout << num << endl;

    system("pause");
    return 0;
}

技術分享圖片

技術分享圖片
template<class _Ty = void>
    struct greater
        : public binary_function<_Ty, _Ty, bool>
    {    // functor for operator>
    bool operator()(const _Ty& _Left, const _Ty& _Right) const
        {    // apply operator> to operands
        return (_Left > _Right);
        }
    };
參照預定義函數greater

3.使用自定義二元函數對象和綁定器《重點》

template<typename T>
void ShowEle(const T& t)    //用於打印容器數據
{
    cout << t << " ";
}

//自定義二元函數對象---數據相加
template<typename T>
class MySumAdd :public binary_function<T, T, int>
{
public:
    int operator()(const T& t1, const T& t2) const
    {
        return t1 + t2;
    }
};
int main()
{
    vector<int> v1, v2, v3;

    for (int i = 0; i < 10;i++)
        v1.push_back(rand() % 30);    //v1數據插入

    //打印數據
    for_each(v1.begin(), v1.end(), ShowEle<int>);
    cout << endl;

    v2.resize(10);

    //將v1中所有數據加2
    transform(v1.begin(), v1.end(), v2.begin(), bind2nd(MySumAdd<int>(), 2));
//打印數據
    for_each(v2.begin(), v2.end(), ShowEle<int>);
    cout << endl;

    system("pause");
    return 0;
}

技術分享圖片

總之:自定義的仿函數和函數配接器搭配使用時,要繼承自template <...> unary_function or template <...> binary_function

unary_function可以作為一個一元函數對象的基類,他定義了兩個模板參數,分別是函數參數類型argument_type和返回值類型result_type,本身並不重載函數符(),由派生類去完成()操作符的重載工作。
binary_function可以作為一個二元函數對象的基類,他定義了三個模板參數,兩個函數參數類型first_argument_type和second_argument_type,以及返回值類型result_type,本身並不重載函數符(),由派生類去完成()操作符的重載工作

STL函數適配器