function類的實現中涉及到的類:
- _Func_base
最頂層的基礎模板類,定義了函數對象在實例複製、轉移上的純虛接口,如Copy、Move等。同時定義了函數調用的虛接口_Do_call。這些純虛接口要求在子類中實現。_Func_base的聲明:
template<class _Rx,
class... _Types>
class _Func_base
{...}
保存了其關聯函數的類型信息,返回值類型Rx,各入參類型列表_Types,這些模板形參在模板類的實現中能夠獲取到。
- _Func_impl
模板子類,實現了_Func_base定義的所有虛接口。其聲明有所不同:
template<class _Callable,
class _Alloc,
class _Rx,
class... _Types>
class _Func_impl final
: public _Func_base<_Rx, _Types...>
在模板形參中多了兩個參數:
_Callable可調用對對象類型,可是函數指針,也可以是實現operator()操作符的可調用實體。
_Alloc內存分配器,負責_Func_impl對象創建時做內存分配。allocator是STL中非常重要的部分,如容器中元素所用內存空間的分配都是由allocator負責,其對內存獲取的方式做了抽象。
A. 可調用對象的保存
在_Func_imp中有如下成員
_Compressed_pair<_Alloc, _Callable> _Mypair;
該成員是一個pair類型,保存內存分配器及可調用類型的對象。_Compressed_pair爲類模板,可適配保存任意類型的可調用對象。_Func_impl僅有如下pubic的構造函數,在構造函數中初始化其Pair成員,何時調用該構造函數在後面說明。
template<class _Other1,
class _Other2>
_Func_impl(_Other1&& _Val, _Other2&& _Ax)
: _Mypair(_One_then_variadic_args_t(),
_STD forward<_Other2>(_Ax), _STD forward<_Other1>(_Val))
{ // construct
}
B. _Func_imp的複製、轉移和調用
複製邏輯如下:
typedef _Func_impl<_Callable, _Alloc, _Rx, _Types...> _Myt;
...
// 小內存類型
template<class _Void>
_Mybase *_Clone(_Void *_Where, false_type) const
{ // return clone of *this, small (locally stored)
_Myalty _Al(_Myax());
_Myt * _Ptr = static_cast<_Myt *>(_Where);
_Al.construct(_Ptr, _Callee(), _Myax());
return (_Ptr);
}
// 大內存類型
template<class _Void>
_Mybase *_Clone(_Void *, true_type) const
{ // return clone of *this, large (dynamically allocated)
_Myalty _Al(_Myax());
_Myt * _Ptr = _Al.allocate(1);
_TRY_BEGIN
_Al.construct(_Ptr, _Callee(), _Myax());
_CATCH_ALL
_Al.deallocate(_Ptr, 1);
_RERAISE;
_CATCH_END
return (_Ptr);
}
在指定內存地址位置_Ptr處,分配並初始化_Func_impl對象。實現上對,內存分配和管理做了優化,通過最後一個入參區分大小內存類型:大內存類型由內存分配器動態分配內存,小內存對象則用入參指定的內存。好處在於,通過入參指定的內存地址是預先分配固定內存,以此避免_Func_impl在創建時頻繁地申請內存。所以本質上還是新實例的拷貝構造,只不過在內存分配上藉助了allocator,隱藏了內存分配細節。這些接口的定義都是爲了配合function對象在轉移或複製時,作爲其內部的成員的_Func_imp完成自身複製。
調用邏輯如下:
_Callable& _Callee() _NOEXCEPT
{ // return reference to wrapped function
return (_Mypair._Get_second()); // !!!返回Pair中保存的Callable對象
}
// 入參爲右值引用,函數調用時使用foward模板做實參轉發
virtual _Rx _Do_call(_Types&&... _Args)
{ // call wrapped function
return (_Invoke_ret(_Forced<_Rx>(), _Callee(),
_STD forward<_Types>(_Args)...));
}
其實就是透傳參數,間接調用Callable對象。可以推測在function對象調用時會透傳給該接口。同時注意的是,其入參是與模板變參列表一致的。
- _Func_class
// TEMPLATE CLASS _Func_class
template<class _Ret,
class... _Types>
class _Func_class
: public _Arg_types<_Types...>
{
...
union _Storage
{ // storage for small objects (basic_string is small)
max_align_t _Dummy1; // for maximum alignment
char _Dummy2[_Space_size]; // to permit aliasing
_Ptrt *_Ptrs[_Num_ptrs]; // _Ptrs[_Num_ptrs - 1] is reserved
};
_Storage _Mystorage;
}
_Func_class是最外層的類,_Storage用於保存了_Func_impl對象。內存上使用union,與_Func_impl的複製轉移的優化策略相匹配:小內存對象時用&_MyStorage作爲預分配內存,否則由分配器動態分配,而且將創建返回的對象地址記錄在_Ptrs[_Num_ptrs-1]中。而且注意到_Func_class的模板形參中並沒有_Callable和_Alloc,說明該兩個形參是在_Func_impl的創建(或拷貝)處通過函數模板形參傳入的。關鍵代碼如下:
protected:
template<class _Fx>
using _Result_of_invoking_t = result_of_t<_Fx(_Types...)>;
template<class _Inv_res>
using _Enable_if_returnable_t = enable_if_t<
is_convertible<_Inv_res, _Ret>::value || is_void<_Ret>::value>;
template<class _Fx>
void _Reset(_Fx&& _Val)
{ // store copy of _Val
_Reset_alloc(_STD forward<_Fx>(_Val), allocator<int>());
}
template<class _Fx,
class _Alloc>
void _Reset_alloc(_Fx&& _Val, const _Alloc& _Ax)
{ // store copy of _Val with allocator
if (!_Test_callable(_Val))
{ // null member pointer/function pointer/std::function
return; // already empty
}
typedef typename decay<_Fx>::type _Decayed;
typedef _Func_impl<_Decayed, _Alloc, _Ret, _Types...> _Myimpl;
_Myimpl *_Ptr = 0;
typedef _Wrap_alloc<_Alloc> _Alimpl0;
typedef typename _Alimpl0::template rebind<_Myimpl>::other _Alimpl;
_Alimpl _Al(_Ax);
_Reset_impl(_STD forward<_Fx>(_Val), _Ax,
_Ptr, _Al, _Is_large<_Myimpl>());
}
template<class _Fx,
class _Alloc,
class _Myimpl,
class _Alimpl>
void _Reset_impl(_Fx&& _Val, const _Alloc& _Ax,
_Myimpl *, _Alimpl& _Al, true_type)
{ // store copy of _Val with allocator, large (dynamically allocated)
_Myimpl *_Ptr = _Al.allocate(1);
_TRY_BEGIN
_Al.construct(_Ptr, _STD forward<_Fx>(_Val), _Ax);
_CATCH_ALL
_Al.deallocate(_Ptr, 1);
_RERAISE;
_CATCH_END
_Set(_Ptr);
}
template<class _Fx,
class _Alloc,
class _Myimpl,
class _Alimpl>
void _Reset_impl(_Fx&& _Val, const _Alloc& _Ax,
_Myimpl *, _Alimpl& _Al, false_type)
{ // store copy of _Val with allocator, small (locally stored)
_Myimpl *_Ptr = static_cast<_Myimpl *>(_Getspace());
_Al.construct(_Ptr, _STD forward<_Fx>(_Val), _Ax);
_Set(_Ptr);
}
bool _Empty() const _NOEXCEPT
{ // return true if no stored object
return (_Getimpl() == 0);
}
_Ptrt *_Getimpl() const _NOEXCEPT
{ // get pointer to object
return (_Mystorage._Ptrs[_Num_ptrs - 1]);
}
如上接口均爲_Func_class中定義的protected接口,後面4)中可以看到function的繼承自_Func_class,通過調用這些接口,實現impl對象的創建、釋放及狀態判斷。在impl的創建上,如上幾個接口的調用關係爲_Reset—— >Reset_alloc——>_Reset_impl,_Cabllable在_Reset調用時傳入,分配器默認是allocator。Reset_impl函數模板,接受Callable和Alloc形參類型,並作爲_Func_impl模板的實參。整個創建過程與_Func_impl的自身複製邏輯類似,都是先分配內存,然後調用_Func_impl的構造函數做初始化,調用關係如下圖。_Func_class是否爲空本質上就是判斷_Reset_impl對象是否爲空。
4. function
至此,終於看到了我們熟悉的function,其定義如下:
// TEMPLATE CLASS _Get_function_impl
template<class _Tx>
struct _Get_function_impl;
#define _GET_FUNCTION_IMPL(CALL_OPT, X1, X2) \
template<class _Ret, \
class... _Types> \
struct _Get_function_impl<_Ret CALL_OPT (_Types...)> \
{ /* determine type from argument list */ \
typedef _Func_class<_Ret, _Types...> type; \
};
_NON_MEMBER_CALL(_GET_FUNCTION_IMPL, , )
#undef _GET_FUNCTION_IMPL
// TEMPLATE CLASS function
template<class _Fty>
class function
: public _Get_function_impl<_Fty>::type
{ // wrapper for callable objects
private:
typedef typename _Get_function_impl<_Fty>::type _Mybase;
通常fuction的使用不會直接指定返回值和形參列表,而是function<Ret(arg1, arg2,…)>的方式,而_Func_class的模板形參中又是Ret和_Types…,如何轉化?這其實就是_Get_function_impl的作用,通過模板偏特化,藉助編譯器的推導能力,從中分離出Ret和_Types…,構建_Func_class,通俗講,“返回值”就是_Func_class<_Ret, _Types…>,所以function是繼承自_Func_class的。緊接着看一個funciton的構造函數:
template<class _Fx,
// 對調用對象的返回做校驗,驗證是否與function中指定的Ret一致
class _Inv_res = typename _Mybase::template _Result_of_invoking_t<_Fx&>,
class = typename _Mybase::template _Enable_if_returnable_t<_Inv_res> >
function(_Fx _Func)
{ // construct wrapper holding copy of _Func
this->_Reset(_STD move(_Func));
}
function(const _Myt& _Right)
{ // construct holding copy of _Right
this->_Reset_copy(_Right);
}
從構造函數可以看出,實現就是調用基類的_Reset接口,以完成_Func_impl對象的創建和初始化。在拷貝構造中,function的拷貝複製過程就是做_Func_impl對象的拷貝和複製。實現上有一個小的細節,調用函數的簽名(返回值和入參)是在類模板的形參列表中指定的,而不是在構造函數function(_Fx _Func)入參類型_Fx中推導出來的,也就是說function對象可以接受任何與template class function中_Fy簽名一致或兼容的調用對象。