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