C++ feels like a new language. ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ-- Bjarne Stroustrup
今天的標題可能不太嚴謹,這裏我借用了Java語言中的說法,熟悉Java的朋友應該都知道方法引用的含義,這裏引入Java 8 in action
中的一段代碼c++
inventory.sort(comparing(Apple::getWeight));
這裏的Apple::getWeight
就是咱們說的方法引用,這裏能夠理解爲咱們將Apple
類的方法getWeight
傳遞給了comparing
,將函數做爲一等公民進行傳遞。git
更準確地說,咱們如何將成員方法應用到STL
算法上?先看一個例子github
struct Cell { explicit Cell(int value) : value_(value) {} int get_value() const { return value; } private: int value_; };
應用算法
std::vector<Cell> inputs = {Cell(3), Cell(10), Cell(113)}; std::vector<int> outputs; std::transform(begin(inputs), end(inputs), back_inserter(outputs), Cell::get_value); //compile error!
咱們知道上面的代碼是沒法經過編譯的,那麼問題來了,在C++中怎麼實現相似的東西。函數
咱們可使用C++2.0
引入的std::function
解決上述沒法經過編譯的問題工具
std::transform(begin(inputs), end(inputs), std::back_inserter(outputs), std::function<int(const Cell&)>(&Cell::get_value));
std::function
接受幾乎全部可調用的東西(自由函數,成員函數,靜態函數,函數對象),並將其包裝在定義一個operator()
的對象中,該對象將調用轉發給包裝的可調用對象。
對於不太清楚std::function
和可調用對象的讀者能夠參考個人另一篇文章可調用對象。網站
一種簡單的方法就是將成員函數包裝在lambda
中指針
std::transform(begin(inputs), end(inputs), back_inserter(outputs), [](const Cell& input) { return input.get_value(); });
這裏說lambda
表達式的實現確實簡單有效,並且正確,我的認爲這麼去作是沒有任何問題的,說它是次優解是由於引入了一個新的變量。code
針對本例,最適合的工具就是std::mem_fn
了。它是C++2.0
以後引入的,能夠取代std::mem_fun
和std::mem_fun_ref
。orm
std::transform(begin(inputs), end(inputs), back_inserter(outputs), std::mem_fn(&Cell::get_value));
上述的寫法看起來跟開篇將到的Java的例子就很相似了。
簡單介紹一下std::mem_fn
、std::mem_fun
和std::mem_fun_ref
std::mem_fn
:C++11之後std::mem_fun
和std::mem_fun_ref
:C++98標準
std::mem_fun
是指針版的把成員函數轉換成函數對象。std::mem_fun_ref
是引用版的把成員函數轉換成函數對象。std::mem_fn
則是不管指針仍是引用均可以把成員函數轉換爲函數對象。
#include <functional>
C++20引入了range庫的概念,咱們看看怎麼用
auto outputs = inputs | ranges::view::transform(&Cell::get_value); // OK
不過遺憾的是,目前主流的C++
編譯器還不支持這種寫法。不過讀者能夠引入range-v3
,用法很是簡單,上面的代碼不用修改,只要將range-v3
的頭文件引入到工程中去,有興趣的讀者能夠自行去研究range-v3
這個庫。
對於range
有興趣的讀者能夠參考這個網站ranges