STL : 仿函數 與 適配器

一 仿函數functor

1. 概述
仿函數(functors)是早期的命名,C++標準規格定案後採用的新名稱是函數對象(function objects)(也就是一種具有函數特質的對象)。

仿函數的作用:在C++的STL提供的各種算法,例如sort()。往往有兩個版本,其中一個是最長用的某種運算的版本(operator<);第二個版本則表現出最泛化的演算流程,允許用戶“以template參數來指定所需要採取的策略”。

仿函數產生的原因:由於函數指針畢竟不能滿足STL對抽象對象的需求,也不能滿足軟件積木的需求——函數指針無法和STL其它組件(如配接器adapter)搭配使用,產生更靈活的變化。
 

template<class T>
class comp:public binary_function<T, T, bool>
{
public:
    bool operator()(T in1, T in2) const
    {
        return (in1>in2);
    }
};


    int a[] = {0, 1, 2, 3, 4, 5, 6,99, 8, 9};
    std::vector<int> v(a, a+10);
    comp<int> comp_object;
    vector<int>::iterator pos;
    pos = find_if(v.begin(), v.end(),bind2nd(comp<int>(), 10));//使用仿函數實現
    
    cout <<comp_object(6, 3) << endl;     //使用對象調用
    cout << comp<int>()(1, 2) << endl;       //使用仿函數實現
    cout <<" the num in v > 10 is " << *pos << endl;       
class my_count1
{
 public:
    T threshold;
    my_count1(T a)
    {
        threshold = a;
    }
    bool operator()(T num)
    {
        return (num < threshold);
    }
};
int main(){


    int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::vector<int> v_a(a, a+10);

    cout << "count: " << std::count_if(v_a.begin(), v_a.end(), my_count1<int>(11)); //bind1st

    return 0;
}

二 函數適配器:

適配器:相當於提供了一個接口,使得某些不適用於特定對象的方法可以被該對象所用,本質上,適配器是使一事物的行爲類似於另一事物的行爲的一種機制。

函數適配器共有如下3種:

1. 綁定器,有兩個:

std::for_each(iterator, iterator, func); 當需要傳入兩個參數給for_each() 時, 需用bind2nd,或bind1st

bind1st  (函數對象,指定值);    (過時)

將指定值綁定到函數對象的第1個參數上。

bind2nd  (函數對象,指定值);   (過時)

將指定值綁定到函數對象的第2個參數上。

bind  (函數對象,指定值… C++11)

綁定的參數的個數不受限制;對於不事先綁定的參數,需要傳std::placeholders進去,從 _1 開始,依次遞增(佔位符)

2. 否定器,也有兩個:

——not1()         //用於逆轉一元斷言

——not2()         //用於逆轉二元斷言

3. 成員函數適配器,也是兩個:

——mem_fun()             //容器參數爲類指針

——mem_fun_ref()        //容器參數爲類對象

綁定的參數的個數不受限制;對於不事先綁定的參數,需要傳std::placeholders進去,從_1開始,依次遞增

4. 函數指針適配器

ptf_fun 將函數指針轉換爲函數對象

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;
class Print_int
{
public:
    void operator()(int &a) const
    {
        cout << a << endl;
    }
};
class Person
{
public:
    Person(string newname, int newage):name(newname), age(newage){}
    void showPerson()const
    {
        cout << "member function: "<< "name " << name << " age " << age << endl;
    }
    string name;
    int age;
};
void print_Person(Person &p)
{
    cout << "name: " << p.name <<endl;
}
void PrintFunc(Person p, int val){
    cout << "ptr_fun() + bind2nd: "<< "p.name " << p.name << " val " << val << endl;
}
class PrintClass: public binary_function< Person, int, void>
{
public:
    void operator()( Person &p, int val)const
    {
        cout<< "fun adaptor + bind2nd: " << "p.name " << p.name << " val " << val << endl;
    }
};
void mystack(){
    vector<int> v(10,2);
    vector<Person> vv;
    vv.reserve(5);
    Person p0("elsa",20);
    Person p1("elsa1",21);
    Person p2("elsa2",22);
    vv.push_back(p0);
    vv.push_back(p1);
    vv.push_back(p2);

    cout << "vv.capacity: " << vv.capacity() << "  vv.size: " << vv.size() <<endl;
    for_each(v.begin(), v.end(), [](int &a){  cout << "lameda: " << a << endl; }); //lameda c++11
    for_each(vv.begin(), vv.end(),print_Person); //function pointer
    for_each(v.begin(), v.end(),Print_int()); //functor
    for_each(vv.begin(), vv.end(),mem_fun_ref(&Person::showPerson)); //member function adaptor

    //  用於傳兩個參數,bind2nd()第二個參數爲 另一參數
    //  用於傳兩個參數,bind1st()第一個參數爲 另一參數

    for_each(vv.begin(), vv.end(),bind2nd(PrintClass(), 50)); //fun adaptor + bind2nd
    for_each(vv.begin(), vv.end(),bind2nd(ptr_fun(PrintFunc), 50)); //ptr_fun adaptor


}

int main(){
    mystack();
    return 0;
}

plus: 1. for_each( iterator, iterator, fun ) , sort(iterator, iterator, fun) 等算法的第三個參數, 若爲函數不需要(), 若爲類則需要().

       2. 掌握functor 的用法

       3.bind2nd 與bind1st

       4. mem_fun  / ptr_fun

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章