C++ 仿函數使用講解
一、問題
先考慮一個簡單的例子:假設有一個vector<string>,你的任務是統計長度小於 5 的string的個數,如果使用count_if函數的話,你的代碼可能長成這樣:
//統計長度小於5的string的個數 bool LengthIsLessThanFive(const string& str) { return str.length()<5; }
int main() { vector<string> vec = { "asdd","asddsa","dssa","asd" }; int res1 = count_if(vec.begin(), vec.end(), LengthIsLessThanFive); }
其中count_if函數的第三個參數是一個函數指針,返回一個bool類型的值。
一般的,如果需要將任意長度的參數也傳入的話,我們可能將函數寫成這樣:
//統計長度小於len的string的個數 bool LengthIsLessThanFive(const string& str, int len) { return str.length()< len; }
這個函數看起來比前面一個版本更具有一般性,但是它不能滿足count_if函數的參數要求:
count_if要求的是僅帶有一個參數的函數指針作為它的最後一個參數,編譯器會報錯
所以問題來瞭,怎麼樣找到以上兩個函數的一個折中的解決方案呢?
二、一般的解決方案
我們考慮用一個全局變量
int maxLength=5; //統計長度小於len的string的個數 bool LenthIsLessThanCustom(const string& str) { return str.length() < maxLength; }
這段代碼看似很不錯,實則不符合規范,更重要的是,它不優雅。原因有以下幾點要考慮:
1、容易出錯;
為什麼這麼說呢,我們必須先初始化maxLength的值,才能繼續接下來的工作,如果我們忘瞭,則可能無法得到正確答案。此外,變量maxLength和函數LengthIsLessThan之間是沒有必然聯系的,編譯器無法確定在調用該函數前是否將變量初始化,給碼農平添負擔。
2、沒有可擴展性;
如果我們每遇到一個類似的問題就新建一個全局變量,尤其是多人合作寫代碼時,很容易引起命名空間污染(namespace polution)的問題;當范圍域內有多個變量時,我們用到的可能不是我們想要的那個。
3、全局變量的問題;
每當新建一個全局變量,即使是為瞭coding的便利,我們也要知道我們應該盡可能的少使用全局變量,因為它的cost很高;而且可能暗示你這裡有一些待解決的優化方案。
三、新的解決方案——仿函數
如果我們不用全局變量,改如何解決這個問題?
先來看仿函數的通俗定義:
仿函數(functor)又稱為函數對象(function object)。是一個能行使函數功能的類。仿函數的語法幾乎和我們普通的函數調用一樣,不過作為仿函數的類,都必須重載operator()運算符,舉個例子:
class Func { public: void operator() (const string& str) const { cout << str << endl; } };
int main() { Func myFunc; myFunc("helloworld!"); }
仿函數其實是使用成員函數的方式解決這個問題,因為成員函數可以很自然的訪問成員變量
所以,對count_if問題
struct ShorterThan { public: explicit ShorterThan(int maxLength) : length(maxLength) {} bool operator() (const string& str) const { return str.length() < length; } private: const int length; }; ; int main() { vector<string> vec = { "asdd","asddsa","dssa","asd" }; int res3 = count_if(vec.begin(), vec.end(), ShorterThan(5)); cout << res3 << endl; }
另一個例子,比較大小
template<typename T> struct comp { bool operator()(T in1, T in2) const { return (in1 > in2); } }; int main() { comp<int> m_comp_objext; cout << m_comp_objext(6, 3) << endl; //一、使用對象調用 cout << comp<int>()(6, 3) << endl; //二、使用臨時對象 return 0; }
解釋:其中第一種用法比較為大傢所熟悉。 comp<int> m_comp_objext的意思是產生一個名為m_comp_objext的對象,m_comp_objext(6,3)則是調用其 operator(),並給予兩個參數6,3。第二種用法中的 comp<int>()意思是產生一個臨時(無名的)對象,之後的(6,3)才是指定兩個參數6,3。
參考:
https://blog.csdn.net/u013049912/article/details/84988027
https://blog.csdn.net/coolwriter/article/details/81533226
到此這篇關於C++ 仿函數使用講解的文章就介紹到這瞭,更多相關C++ 仿函數使用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!