轉自 http://www.hankcs.com/program/cpp/c11-std-function-usage.html
function可以將普通函數,lambda表達式和函數對象類統一起來。它們並不是相同的類型,然而通過function模板類,可以轉化為相同類型的對象(function對象),從而放入一個map里。
在看Cocos2d-x的范例代碼時,隨處可見“很奇怪”的語法:
static std::function<Layer*()> createFunctions[] = { CL(CameraTest1), //... };
其中CL是一個宏,對應如下lambda表達式:
- #define CL(__className__) [](){ return __className__::create();}
還算好懂,感覺是個工廠模式,同時用宏模擬了接口。
但是這個std::function<Layer*()>卻讓我少見多怪了,翻開第五版《C++ Primer》,才知道原來是C++11的新特性——可調用對象模板類。一句話說明問題,std::function<Layer*()>代表一個可調用對象,接收0個參數,返回Layer*。
至於function的深入理解,還是用代碼說明吧。
#include <iostream> #include <map> #include <functional> using namespace std; // 普通函數 int add(int i, int j) { return i + j; } // lambda表達式 auto mod = [](int i, int j){return i % j; }; // 函數對象類 struct divide { int operator() (int denominator, int divisor) { return denominator / divisor; } }; ///////////////////////////SubMain////////////////////////////////// int main(int argc, char *argv[]) { // 受限的map map<char, int(*)(int, int)> binops_limit; binops_limit.insert({ '+', add }); binops_limit.insert({ '%', mod }); // 錯誤 1 error C2664: “void std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::insert(std::initializer_list<std::pair<const _Kty,_Ty>>)”: 無法將參數 1 從“initializer-list”轉換為“std::pair<const _Kty,_Ty> &&” // binops_limit.insert({ '%', divide() }); // 更靈活的map map<char, function<int(int, int)>> binops = { { '+', add }, { '-', minus<int>() }, { '*', [](int i, int j){return i - j; } }, { '/', divide() }, { '%', mod }, }; cout << binops['+'](10, 5) << endl; cout << binops['-'](10, 5) << endl; cout << binops['*'](10, 5) << endl; cout << binops['/'](10, 5) << endl; cout << binops['%'](10, 5) << endl; system("pause"); return 0; } ///////////////////////////End Sub//////////////////////////////////
如上所示,function可以將普通函數,lambda表達式和函數對象類統一起來。它們並不是相同的類型,然而通過function模板類,可以轉化為相同類型的對象(function對象),從而放入一個map里。
另外我實際測試的結果來看,在VS2013編譯器下,上述代碼可以通過,而第五版《C++ Primer》第512頁第一行所言“錯誤:mod不是一個函數指針”並沒有發生錯誤,有可能是對C++11標准的不同實現吧。
