std::functional
的基本原理:
std::functional
原理分析:
可调用对象:
类型
举例
可传给 std::function
说明
普通函数指针
int(*)(int,int)
✅
最基础
Lambda
[=](int x){ return x+1; }
✅
最常用
函数对象
struct F { int operator()(); };
✅
可定制行为
静态成员函数
static int f()
✅
和普通函数等价
成员函数指针
&Class::method
❌(需要包装)
必须配合对象使用
std::bind
结果
bind(f, 1, _1)
✅
预设参数
std::mem_fn
结果
mem_fn(&C::f)
✅
成员函数包装
std::function
本身
function<void()>
✅
高阶封装
类型擦除:
std::decay_t<T>
是 C++ 类型萃取中非常常用的工具,它会把一个类型 退化(decay) 成适用于函数参数传递的形式,其行为类似于函数参数的默认类型转换规则 。可以理解为:std::decay_t<T>
会去掉引用、cv 限定符、数组/函数类型退化为指针等。
Function的实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #pragma once #include <memory> #include <utility> #include <type_traits> template <typename >class Function ; template <typename R, typename ... Args>class Function <R (Args...)> { class ICallable { public : virtual R invoke (Args&&... args) = 0 ; virtual std::unique_ptr<ICallable> clone () const = 0 ; virtual ~ICallable () = default ; }; template <typename F> class CallableImpl : public ICallable { F func; public : explicit CallableImpl (F&& f) : func(std::forward<F>(f)) { } R invoke (Args&&... args) override { return func (std::forward<Args>(args)...); } std::unique_ptr<ICallable> clone () const override { return std::make_unique<CallableImpl<F>>(F (func)); } }; std::unique_ptr<ICallable> callable; public : Function () noexcept = default ; template <typename F, typename = std::enable_if_t <!std::is_same<std::decay_t <F>, Function>::value>> Function (F&& f) : callable (std::make_unique<CallableImpl<std::decay_t <F>>>(std::forward<F>(f))) {} Function (Function&& other) noexcept = default ; Function& operator =(Function&& other) noexcept = default ; Function (const Function& other) : callable (other.callable ? other.callable->clone () : nullptr ) {} Function& operator =(const Function& other) { if (this != &other) { callable = other.callable ? other.callable->clone () : nullptr ; } return *this ; } R operator () (Args... args) { if (!callable) { throw std::bad_function_call (); } return callable->invoke (std::forward<Args>(args)...); } explicit operator bool () const { return static_cast <bool >(callable); } };
代码说明 ICallable
是所有可调用对象的抽象包裹wrapper
类,是一个基类。在Function中,通过*ICallable
指针(或者智能指针)来调用派生类中的invoke
函数,来实现最后的执行
1 2 3 4 5 6 7 template <typename R, typename ... Args> class ICallable { public : virtual R invoke (Args&&... args) = 0 ; virtual std::unique_ptr<ICallable> clone () const = 0 ; virtual ~ICallable () = default ; };
CallableImpl
是基于ICallable
的派生类,里面实现了具体的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template <typename R, typename ... Args> template <typename F>class CallableImpl : public ICallable { F func; public : explicit CallableImpl (F&& f) : func(std::forward<F>(f)) { } R invoke (Args&&... args) override { return func (std::forward<Args>(args)...); } std::unique_ptr<ICallable> clone () const override { return std::make_unique<CallableImpl<F>>(F (func)); } };
然后是Function内容的实现:
首先私有变量采用了unique_ptr
的设计,来管理类型为基类指针但是指向子类的指针。
单参构造函数:explicit Function(F&& f)
,在上面使用了SFINAE(substitute failure is not an error)
,即在进行模板匹配的时候,如果发生了模板不匹配,则不认为是一种错误,转而匹配其他的构造函数。(在其他的设计中也有体现,比如std::lock_guard
和std::unique_lock
,两者都要求传入的类实现lock
和unlock
方法。)
讲到构造函数匹配的问题:下面是构造函数的匹配规则
匹配类别
优先级
非模板函数
最高
模板函数(精确匹配)
高
模板函数(万能引用 T&&
)
较低(仅在无其他更优时选)
可变参数模板 (...
)
最低
为什么要实现辅助的clone
函数呢?
在这里可见,在赋值构造和赋值拷贝中,调用的是callable实际指向对象的clone函数,如果不这样,默认的赋值构造与拷贝实现的是浅拷贝,那么会引发一系列的问题
为什么要重载R operator()(Args... args)
呢?
通过重载这个运算符,来包裹invoke函数,那么就可以直接使用f()的方式调用函数,实现可调用对象的完美还原(不改变使用方式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 template <typename >template <typename R, typename ... Args>class Function <R (Args...)> { class ICallable ; template <typename F> class CallableImpl : public ICallable; std::unique_ptr<ICallable> callable; public : Function () noexcept = default ; template <typename F, typename = std::enable_if_t <!std::is_same<std::decay_t <F>, Function>::value>> Function (F&& f) : callable (std::make_unique<CallableImpl<std::decay_t <F>>>(std::forward<F>(f))) {} Function (Function&& other) noexcept = default ; Function& operator =(Function&& other) noexcept = default ; Function (const Function& other) : callable (other.callable ? other.callable->clone () : nullptr ) {} Function& operator =(const Function& other) { if (this != &other) { callable = other.callable ? other.callable->clone () : nullptr ; } return *this ; } R operator () (Args... args) { if (!callable) { throw std::bad_function_call (); } return callable->invoke (std::forward<Args>(args)...); } explicit operator bool () const { return static_cast <bool >(callable); } };