本文原文link: https://www.wolai.com/8FYKXwcp1ozZnwXc6ThL75#rZ6NcsSCroiH83XhoKSaGB
1 类图·
classDiagram
_Function_base <|-- function
_Base_manager --* _Function_base
_Base_manager <|-- _Function_handler
_Function_handler <.. function
class _Function_base {
// 存储可调用实体,管理可调用实体的生命周期
+class _Base_manager 内部类
#_M_functor: _Any_data(存储可调用对象或其指针)
#_M_manager: _Manager_type
}
class function {
-_M_invoker: Invoker_type, 函数指针,指向function_handler的_M_invoke()
}
class _Base_manager~_Functor~ {
// 一堆static函数,包括构造,析构可调用实体等
+_M_manager()
+_Functor* _M_get_pointer()
+_M_init_functor()
+_M_not_empty_function()
#_M_destroy()
}
class _Function_handler{
// 代理Manager,+可调用实体在调用时做转发
+ _M_invoke()
}
2 function的定义·
1 2 3 4 5 6 7 8 9 10 11 template <typename _Res, typename ... _ArgTypes> class function <_Res(_ArgTypes...)> : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>, private _Function_base
父类有两个 _Maybe_unary_or_binary_function
和 _Function_base
模板参数分别是代表返回值的 _Res
和 代表参数的 ..._ArgTypes
3 _Function_base·
定义如下:
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 class _Function_base { public : static const std::size_t _M_max_size = sizeof (_Nocopy_types); static const std::size_t _M_max_align = __alignof__(_Nocopy_types); template <typename _Functor> class _Base_manager { ... }; _Function_base() : _M_manager(nullptr ) { } ~_Function_base() { if (_M_manager) _M_manager(_M_functor, _M_functor, __destroy_functor); } bool _M_empty() const { return !_M_manager; } typedef bool (*_Manager_type) (_Any_data&, const _Any_data&, _Manager_operation) ; _Any_data _M_functor; _Manager_type _M_manager; }
有两个成员变量,一个是_M_functor
,类型是 _Any_data
, 另一个是 _M_manager
,类型是 _Manager_type
1 2 typedef bool (*_Manager_type) (_Any_data&, const _Any_data&, _Manager_operation) ;
3.1 _Any_data
·
先看类型 _Any_data
:
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 union _Nocopy_types { void * _M_object; const void * _M_const_object; void (*_M_function_pointer)(); void (_Undefined_class::*_M_member_pointer)(); }; union [[gnu::may_alias]] _Any_data { void * _M_access() { return &_M_pod_data[0 ]; } const void * _M_access() const { return &_M_pod_data[0 ]; } template <typename _Tp> _Tp& _M_access() { return *static_cast <_Tp*>(_M_access()); } template <typename _Tp> const _Tp& _M_access() const { return *static_cast <const _Tp*>(_M_access()); } _Nocopy_types _M_unused; char _M_pod_data[sizeof (_Nocopy_types)]; };
_Any_data
代表可调用对象。内部封装了四种可调用类型。
sizeof(_Any_data)
为16字节,因为成员函数指针的大小可能是16B。
alignof(_Any_data)
为8字节,平台(gcc 8.3, intel 64位架构)
3.2 _Base_manager
·
后续一节中会使用到本class,本节先介绍。
3.2.1 _M_not_empty_function
·
判定传入的function 是否为空,针对不同可调用类型,做了几个重载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <typename _Signature> static bool _M_not_empty_function(const function<_Signature> &__f) { return static_cast <bool >(__f); } template <typename _Tp> static bool _M_not_empty_function(_Tp *__fp) { return __fp != nullptr ; } template <typename _Class, typename _Tp>static bool _M_not_empty_function(_Tp _Class::*__mp) { return __mp != nullptr ; } template <typename _Tp> static bool _M_not_empty_function(const _Tp &) { return true ; }
3.2.2 _M_init_functor
·
初始化functor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 protected : static void _M_init_functor(_Any_data &__functor, _Functor &&__f) { _M_init_functor(__functor, std::move (__f), _Local_storage()); } private : static void _M_init_functor(_Any_data &__functor, _Functor &&__f, true_type) { ::new (__functor._M_access()) _Functor(std::move (__f)); } static void _M_init_functor(_Any_data &__functor, _Functor &&__f, false_type) { __functor._M_access<_Functor *>() = new _Functor(std::move (__f)); }
这里根据是否能 _Local_storage
路由到不同的private
函数中。
如果能local storage
, 则在传入的_Any_data
functor内部直接placement new
一个_Functor
,否则在heap
上直接new,然后_Any_data
内部的指针指向这个heap
new出来的对象。
这里的_Local_storage
如何实现的?
1 2 3 4 5 6 7 8 9 10 11 static const std::size_t _M_max_size = sizeof (_Nocopy_types);static const std::size_t _M_max_align = __alignof__(_Nocopy_types); static const bool __stored_locally = (__is_location_invariant<_Functor>::value && sizeof (_Functor) <= _M_max_size && __alignof__(_Functor) <= _M_max_align && (_M_max_align % __alignof__(_Functor) == 0 )); typedef integral_constant<bool , __stored_locally> _Local_storage;
本质上用的integral_constant
, 为true_type的条件是:
__is_location_invariant
, 实际上就是 __is_trivially_copyable
sizeof functor不能超过 _M_max_size
, 即: sizeof(_Nocopy_types), 也即 sizeof(_Any_data), 通常是16字节。
alignof functor是小于等于 alignof _Nocopy_types, 即8字节。且可按8字节整除。
强调下,这里的alignof,sizeof都是平台相关的,不同平台可能不一样。
这些限制都是为了functor能够placement new
到 _Any_data
上,避免多一次内存申请开销。
3.3 _M_destroy
·
根据是否local storage
调用对应的析构函数:
1 2 3 4 5 6 7 8 9 10 static void _M_destroy(_Any_data &__victim, true_type) { __victim._M_access<_Functor>().~_Functor(); } static void _M_destroy(_Any_data &__victim, false_type) { delete __victim._M_access<_Functor *>(); }
3.4 _M_get_pointer
·
获取 source
中存放的可调用对象指针。
1 2 3 4 5 6 7 8 9 static _Functor *_M_get_pointer(const _Any_data &__source) { const _Functor *__ptr = __stored_locally ? std::__addressof(__source._M_access<_Functor>()) : __source._M_access<_Functor *>(); return const_cast <_Functor *>(__ptr); }
如果__source
中存放的可调用对象是存放在本地的,则直接返回该对象的地址(这里必须用std::__addressof
, 因为&可能被重载了)。如果不是,则返回指针。
3.5 _M_manager
·
一个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 enum _Manager_operation { __get_type_info, __get_functor_ptr, __clone_functor, __destroy_functor }; static bool _M_manager(_Any_data &__dest, const _Any_data &__source, _Manager_operation __op) { switch (__op) { #if __cpp_rtti case __get_type_info: __dest._M_access<const type_info *>() = &typeid (_Functor); break ; #endif case __get_functor_ptr: __dest._M_access<_Functor *>() = _M_get_pointer(__source); break ; case __clone_functor: _M_clone(__dest, __source, _Local_storage()); break ; case __destroy_functor: _M_destroy(__dest, _Local_storage()); break ; } return false ; }
4 _Function_handler
·
function_handler是一个代理类,负责可调用实体在调用时的转发。
声明如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <typename _Signature, typename _Functor> class _Function_handler ;template <typename _Res, typename _Functor, typename ... _ArgTypes>class _Function_handler <_Res(_ArgTypes...), _Functor> : public _Function_base::_Base_manager<_Functor> { typedef _Function_base::_Base_manager<_Functor> _Base; public : static _Res _M_invoke(const _Any_data &__functor, _ArgTypes &&...__args) { return (*_Base::_M_get_pointer(__functor))( std::forward<_ArgTypes>(__args)...); } }; ...
继承自 _Function_base::_Base_manager
,拥有构造、析构可调用实体的能力。
内部只有一个_M_invoke
函数,通过_M_get_pointer
获取可调用实体的指针,然后执行forward
args来调用。
4.1 偏特化1 - void 类型返回值·
void前不用return
1 2 3 4 5 6 7 8 9 10 11 12 template <typename _Functor, typename ... _ArgTypes>class _Function_handler <void (_ArgTypes...), _Functor> : public _Function_base::_Base_manager<_Functor> { typedef _Function_base::_Base_manager<_Functor> _Base; public : static void _M_invoke(const _Any_data &__functor, _ArgTypes &&...__args) { (*_Base::_M_get_pointer(__functor))(std::forward<_ArgTypes>(__args)...); } };
4.2 偏特化2 - 成员函数·
成员函数不能简单像primary template那样调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 template <typename _Class, typename _Member, typename _Res, typename ... _ArgTypes> class _Function_handler <_Res(_ArgTypes...), _Member _Class::*> : public _Function_handler<void (_ArgTypes...), _Member _Class::*> { typedef _Function_handler<void (_ArgTypes...), _Member _Class::*> _Base; public : static _Res _M_invoke(const _Any_data &__functor, _ArgTypes &&...__args) { return std::__invoke(_Base::_M_get_pointer(__functor)->__value, std::forward<_ArgTypes>(__args)...); } };
用std::invoke
包装了一层, std::invoke
可以处理所有函数。
为什么不直接用std::invoke
处理primary template?是因为std::invoke
有额外开销吗?
5 function 构造函数·
这里只分析常用构造函数,即传入一个Functor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template <typename _Functor, typename = _Requires<__not_<is_same<_Functor, function>>, void >, typename = _Requires<_Callable<_Functor>, void >> function (_Functor);
_Requires
实际上就是enable_if
1 2 3 template <typename _Cond, typename _Tp>using _Requires = typename enable_if<_Cond::value, _Tp>::type;
这是一个模板构造函数, 模板生效条件是:
传入Functor不能本身就是function(不然就是拷贝构造函数了)
传入的Functor本身要是 _Callable
的
_Callable
相关的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 template <typename _From, typename _To> using __check_func_return_type = __or_<is_void<_To>, is_same<_From, _To>, is_convertible<_From, _To>>; template <typename _Func, typename _Res2 = typename result_of<_Func&(_ArgTypes...)>::type> struct _Callable : __check_func_return_type<_Res2, _Res> { }; template <typename _Tp> struct _Callable <function, _Tp> : false_type { };
result_of 得到 Func调用的返回类型(注意这里Func后面必须跟&, 这是result_of的弊端,c++17之后推荐使用invole_result)。
_Callable
检测 std::function
传入的返回值和Func
函数调用后的返回值是否相同(或者是void类型,又或者可能隐私转换),如果相同 _Callable
持有value=true
,否则value=false
回到构造函数实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 template <typename _Res, typename ... _ArgTypes> template <typename _Functor, typename , typename >function<_Res(_ArgTypes...)>::function (_Functor __f) : _Function_base() { typedef _Function_handler<_Res(_ArgTypes...), _Functor> _My_handler; if (_My_handler::_M_not_empty_function(__f)) { _My_handler::_M_init_functor(_M_functor, std::move (__f)); _M_invoker = &_My_handler::_M_invoke; _M_manager = &_My_handler::_M_manager; } }
首先构造基类。 接着对 _Function_handler
做了typedef
。
调用 _M_not_empty_function
,如果非空,再调用_M_init_functor
, 这一步执行完后:
_M_functor
要么本身就存储了 __f
的信息(只要__f
本身满足 local storage 的要求。要么指向一个新new
出来的__f
对象。
接着, 函数指针 _M_invoker
指向了 _My_handler::_M_invoke . _M_manager
指向 _My_handler::_M_manager 函数。
6 function调用 — operator()·
函数定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 _Res operator () (_ArgTypes... __args) const ; template <typename _Res, typename ... _ArgTypes>_Res function<_Res(_ArgTypes...)>::operator ()(_ArgTypes... __args) const { if (_M_empty()) __throw_bad_function_call(); return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...); }
这个没什么好说的,只要function不为空,则转发调用。
7 function析构·
ffunction本身没有析构函数, 查看其基类 Function_base
的析构:
1 2 3 4 5 ~_Function_base() { if (_M_manager) _M_manager(_M_functor, _M_functor, __destroy_functor); }
我们在 这里 提到了 _M_manager
, 实际上最终进入 _M_destroy
8 总结·
本文档介绍了C++标准库中的std::function类及其相关概念。std::function提供了一种通用的方式来包装任何可调用的对象,并支持动态绑定。文档首先定义了一个基础类_Function_base,用于存储可调用的对象或其指针,同时提供管理其生命周期的函数。接着,function类作为_Function_base的子类,提供了对可调用对象的操作,如调用和传递参数。
_Function_base包含两个主要成员变量:_M_functor用于存储可调用的对象或其指针,而_M_manager则指向管理_M_functor生命周期的管理类。管理类_Base_manager提供了诸如创建、复制、销毁和查询类型信息等功能。
_Function_handler是一个简单的代理类,用于在调用时转发给定的_M_functor。它从_Function_base继承并添加了一个仅有的成员函数_M_invoke,该函数通过_M_get_pointer获取_M_functor的指针,然后调用相应的函数。文档还详细讨论了function类的常见构造方式,特别是当传入一个可调用对象(例如函数指针或成员函数指针)时的情况。总体来说,std::function的设计允许用户以一种类型安全的方式处理可调用对象,同时也提供了一套机制来确保这些对象能够在运行时正确地进行动态绑定和管理。