介绍 C++ lambda、仿函数、std::function 等。
仿函数
仿函数(functor),实际上是一个定义了运算符operator()
的类。
1 | struct Foo |
仿函数不是函数,std::is_function
返回false_type
。
Functor Adaptor
std::function的实现
《STL源码解析》一书首先介绍了诸如binary_function
、unary_function
之类的,注意到里面诸如argument_type
、result_type
的成员都在C++17中被deprecated了,原因是现在C++中的完美转发和decltype
已经能够很好地解决这个问题了,所以我们不要计较这个细节。<functional>
中还定义了诸如plus
、minus
、multiplies
、divides
、modulus
、negate
等数学函数和诸如equal_to
、less
等比较函数,我们常见是用法是作为一个predicate,也就是sort(v.begin(), v.end(), greater<int>());
,此外还实现了一些函数式的函数,例如identity
、select
(类似car或者head)、project
等。
类型擦除
说到std::function
的实现,必须要提一下类型擦除的机制。以std::any
这样的机制为例,它可以储存任何形式的对象,在C++17之后由于有了构造函数的模板推导,事情不太一样了,可以直接用个模板,然后加一些乱七八糟的casting。
1 | template <typename T> |
不过不考虑这些,因为假设std::any
是一个非模板类,那么现在就面临如何存储的问题,一种方法是用void *
,不过这样会丢失类型信息。
1 | struct my_any { |
于是引入一层间接,也就是将实际盛放T
的模板类holder<T>
继承一个placeholder
,于是就可以通过操作placeholder
来操作holder<T>
了。与此对应的机制还有智能指针实现中著名的T: public enable_shared_from_this<T>
,具体可以查看我的博文
1 | class placeholder |
std::function中的类型擦除
为什么std::function
中会需要类型擦除呢?首先我们知道C++中的Callable或者说Invokable的对象主要有函数指针、函数对象和lambda几类,而这三个的类型不尽相同,lambda更是每一个lambda都具有一个类型。