仿函數——Functor

簡單的需求

好比,有一個簡單需求:找到一個vector<string>中,長度小於3的字符串的數目。解決方法可能會是:less

int count(const std::vector<std::string>& str_vec, const size_t threshold)
    {
        int size = 0;
        std::vector<std::string>::const_iterator it; 
        for (it = str_vec.begin(); it != str_vec.end(); ++ it) {
            if (it->length() < threshold) {
                ++ size;
            }   
        }   
        return size;
    }

其實,數據STL的同窗應該知道有個count_if函數。count_if的功能就是對於某種容器,對符合條件的元素進行計數。count_if包含三個參數,容器的開始地址、容器的結束地址、以及參數爲元素類型的函數。函數

使用count_if的代碼能夠這樣寫:spa

bool test(const std::string& str) { return str.length() < 3; }
    int count(const std::vector<std::string>& str_vec)
    {
        return std::count_if(str_vec.begin(), str_vec.end(), test);
    }

可是,這樣有個問題:沒有擴展性。好比,判斷的字符串由長度3變成5呢?將test函數上面再增長一個長度參數能夠嗎?不行,count_if的實現就決定了test必須是單一參數的。既想知足count_if
的語法要求,又須要讓判斷的函數具備可擴展性,這時候就須要functor了。code

functor登場

functor的含義是:調用它就像調用一個普通的函數同樣,不過它的本質是一個類的實例的成員函數(operator()這個函數),因此functor也叫function object
所以如下代碼的最後兩個語句是等價的:three

class SomeFunctor
    {
    public:
        void operator() (const string& str)
        {
            cout << "Hello " << str << end;
        }
    };

    SomeFunctor functor;
    functor("world");               //Hello world
    functor.operator()("world");    //Hello world

其實,它並不算是STL中的一部分,不過須要STL中的函數都把functor所謂參數之一,functor起到了定製化的做用。functor與其它普通的函數相比,有一個明顯的特色:可使用成員變量。這樣,就提供了擴展性。字符串

繼續上面例子,寫成functor的形式:get

class LessThan
    {
    public:
        LessThan(size_t threshold): _threshold(threshold) {}
        bool operator() (const std::string str) { return str.length() < _threshold; }
    private:
        const size_t _threshold;
    };

    int count(const std::vector<std::string>& str_vec)
    {
        LessThan less_than_three(3);
        return std::count_if(str_vec.begin(), str_vec.end(), less_than_three);
        //LessThan less_than_five(5);
        //std::count_if(str_vec.begin(), str_vec.end(), less_than_five);
    }

    int count_v2(const std::vector<std::string>& str_vec, const size_t threshold)
    {
        return std::count_if(str_vec.begin(), str_vec.end(), LessThan(threshold));
    }

C++11的新玩法

有人可能會說,我已經有了本身實現的判斷函數了,可是直接用又不行,有啥解決辦法嗎?
實際上是有的!(我也是最近才發現的)string

C++11的標準中,提供了一套函數,能將一個普通的、不符合使用方要求的函數,轉變成一個符合參數列表要求的functor,這實在是太酷了!it

好比用戶本身實現的int test(const std::string& str_vec, const size_t threshold)函數,若是能將第二個參數進行綁定,不就符合count_if的要求了嗎?io

新標準的C++就提供了這樣一個函數——bind

經過std::bind以及std::placeholders,就能夠實現轉化,樣例代碼以下:

bool less_than_func(const std::string& str, const size_t threshold)
    {
            return str.length() < threshold;
    }

    //提供 _1 佔位符
    using namespace std::placeholders;                              
    //綁定less_than_func第二個參數爲5, 轉化爲functor
    auto less_than_functor = std::bind(less_than_func, _1, 5); 
    std::cout << std::count_if(str_vec.begin(), str_vec.end(), less_than_functor) << std::endl;

參考資料

--EOF--

相關文章
相關標籤/搜索