這篇文章主要介紹“C++11中的std::function怎么用”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“C++11中的std::function怎么用”文章能幫助大家解決問題。
創(chuàng)新互聯(lián)公司長期為上1000家客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為開化企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè),開化網(wǎng)站改版等技術(shù)服務(wù)。擁有十年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
本文是基于gcc-4.9.0的源代碼進行分析,std::function是C++11才加入標(biāo)準(zhǔn)的,所以低版本的gcc源碼是沒有std::function的,建議選擇4.9.0或更新的版本去學(xué)習(xí),不同版本的gcc源碼差異應(yīng)該不小,但是原理和設(shè)計思想的一樣的。
類模版std::function是一種通用的多態(tài)函數(shù)包裝器。std::function的實例可以對任何可以調(diào)用的目標(biāo)實體進行存儲、復(fù)制、和調(diào)用操作,這些目標(biāo)實體包括普通函數(shù)指針、類成員函數(shù)指針(第一個參數(shù)需要傳入對應(yīng)的this指針)、Lambda表達式或者某個類的實例(前提是這個類重載了()運算符)。std::function對象是對C++中現(xiàn)有的可調(diào)用實體的一種類型安全的包裹(我們知道像函數(shù)指針這類可調(diào)用實體,是類型不安全的)。
通常std::function是一個函數(shù)對象類,它包裝其它任意的可調(diào)用實體,被包裝的對象具有類型為T1,…,TN的N個參數(shù),并且返回一個可轉(zhuǎn)換到R類型的值。std::function使用模板轉(zhuǎn)換構(gòu)造函數(shù)接收被包裝的函數(shù)對象;特別是,閉包類型可以隱式地轉(zhuǎn)換為std::function。最簡單的理解就是通過std::function對C++中各種可調(diào)用實體的封裝,形成一個新的可調(diào)用的std::function對象,讓我們不再糾結(jié)那么多的可調(diào)用實體之間如何進行方便高效的轉(zhuǎn)換。
std::function位于libstdc++-v3\include\std\functional中
templateclass function<_Res(_ArgTypes...)> : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>, private _Function_base { typedef _Res _Signature_type(_ArgTypes...); template using _Invoke = decltype(__callable_functor(std::declval<_Functor&>())(std::declval<_ArgTypes>()...) ); template using _Callable = __check_func_return_type<_Invoke<_Functor>, _Res>; template using _Requires = typename enable_if<_Cond::value, _Tp>::type; public: typedef _Res result_type; function() noexcept :_Function_base() { } function(nullptr_t) noexcept :_Function_base() { } template function(const function& __x) :_Function_base() { if (static_cast (__x)) { _M_invoker = __x._M_invoker; _M_manager = __x._M_manager; __x._M_manager(_M_functor, __x._M_functor, __clone_functor); } } function(function&& __x) :_Function_base() { __x.swap(*this); } template , void>> function(_Functor __f) { typedef _Function_handler<_Signature_type, _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& operator=(const function& __x) { function(__x).swap(*this); return *this; } function& operator=(function&& __x) { function(std::move(__x)).swap(*this); return *this; } function& operator=(nullptr_t) { if (_M_manager) { _M_manager(_M_functor, _M_functor, __destroy_functor); _M_manager = 0; _M_invoker = 0; } return *this; } template _Requires<_Callable<_Functor>, function&> operator=(_Functor&& __f) { function(std::forward<_Functor>(__f)).swap(*this); return *this; } template function& operator=(reference_wrapper<_Functor> __f) noexcept { function(__f).swap(*this); return *this; } void swap(function& __x) { std::swap(_M_functor, __x._M_functor); std::swap(_M_manager, __x._M_manager); std::swap(_M_invoker, __x._M_invoker); } explicit operator bool() const noexcept { return !_M_empty(); } _Res operator()(_ArgTypes... __args) const; { if (_M_empty()) __throw_bad_function_call(); return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...); } private: typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...); _Invoker_type _M_invoker;
從源代碼中可以看出以下幾點信息:
該類是一個可變參模板類
該類繼承于_Maybe_unary_or_binary_function(不分析)和_Function_base,類成員只有_M_invoker一個,從定義可以看出這是一個標(biāo)準(zhǔn)的函數(shù)指針
首先分析operator()方法,平時開發(fā)中std::function使用最多的肯定就是重載的括號運算符了,畢竟最終也是要把它當(dāng)成類似于函數(shù)的形式來調(diào)用的??梢钥吹給perator()函數(shù)里面調(diào)用了_M_invoker函數(shù),并沒有什么特殊的處理
既然_M_invoker能被調(diào)用,那就說明它肯定被初始化過了,從調(diào)用時傳給他的參數(shù)來看,多了一個不知道是什么的參數(shù)_M_functor,所以我們可以猜測_M_invoker并不是直接指向std::function接管的可調(diào)用實體的,而是一個類似中間層的東西,在_M_invoker的實現(xiàn)里面才調(diào)用了我們需要執(zhí)行的那個真實的可調(diào)用實體
只有構(gòu)造函數(shù)function(_Functor __f)對_M_invoker進行了初始化,而使用的就是std::_Function_handler里的方法來初始化_M_invoker的,std::_Function_handler的實現(xiàn)在后面會講到
還是看構(gòu)造函數(shù)function(_Functor __f),因為std::function的目的就是對我們傳入的可調(diào)用實體進行包裝,這里說的可調(diào)用實體可以是普通函數(shù)指針、類成員函數(shù)指針(第一個參數(shù)需要傳入對應(yīng)的this指針)、Lambda表達式以及某個類實例(前提是這個類重載了()運算符),而我們看到在std::function這個類里面并沒有直接托管我們傳入的可調(diào)用實體,而只是調(diào)用了_My_handler::_M_init_functor(_M_functor, std::move(__f)),推測是由_Function_base來托管可調(diào)用實體的
std::_Function_handler位于libstdc++-v3\include\std\functional中
templateclass _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)...); } }; template class _Function_handler : 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)...); } }; template class _Function_handler<_Res(_ArgTypes...), reference_wrapper<_Functor> > : public _Function_base::_Ref_manager<_Functor> { typedef _Function_base::_Ref_manager<_Functor> _Base; public: static _Res _M_invoke(const _Any_data& __functor, _ArgTypes... __args) { return __callable_functor(**_Base::_M_get_pointer(__functor))(std::forward<_ArgTypes>(__args)...); } }; template class _Function_handler > : public _Function_base::_Ref_manager<_Functor> { typedef _Function_base::_Ref_manager<_Functor> _Base; public: static void _M_invoke(const _Any_data& __functor, _ArgTypes... __args) { __callable_functor(**_Base::_M_get_pointer(__functor))(std::forward<_ArgTypes>(__args)...); } }; template class _Function_handler<_Res(_ArgTypes...), _Member _Class::*> : public _Function_handler { typedef _Function_handler _Base; public: static _Res _M_invoke(const _Any_data& __functor, _ArgTypes... __args) { return std::mem_fn(_Base::_M_get_pointer(__functor)->__value)(std::forward<_ArgTypes>(__args)...); } }; template class _Function_handler : public _Function_base::_Base_manager<_Simple_type_wrapper< _Member _Class::* > > { typedef _Member _Class::* _Functor; typedef _Simple_type_wrapper<_Functor> _Wrapper; typedef _Function_base::_Base_manager<_Wrapper> _Base; public: static bool _M_manager(_Any_data& __dest, const _Any_data& __source, _Manager_operation __op) { switch (__op) { #ifdef __GXX_RTTI case __get_type_info: __dest._M_access () = &typeid(_Functor); break; #endif case __get_functor_ptr: __dest._M_access<_Functor*>() = &_Base::_M_get_pointer(__source)->__value; break; default: _Base::_M_manager(__dest, __source, __op); } return false; } static void _M_invoke(const _Any_data& __functor, _ArgTypes... __args) { std::mem_fn(_Base::_M_get_pointer(__functor)->__value)(std::forward<_ArgTypes>(__args)...); } };
從源代碼中可以看出_Function_handler有六種重載形式,以下對其進行分類說明:
第一個和第二個重載形式繼承于std::_Function_base::_Base_manager,當(dāng)std::function接管的可調(diào)用實體是一個普通函數(shù)指針、類實例或者Lambda表達式時,發(fā)揮作用的就是這兩個類。里面的內(nèi)容很簡單,通過調(diào)用_Function_base::_Base_manager<_Functor>的_M_get_pointer方法從__functor中取出對應(yīng)的可調(diào)用實體,然后直接執(zhí)行,我們知道能直接執(zhí)行的可調(diào)用實體的類型是普通函數(shù)指針、類實例(必須重載了()運算符)或者Lambda表達式(Lambda其實本質(zhì)就是一個匿名的類實例)。這兩個重載形式的唯一區(qū)別就是它們一個處理函數(shù)有返回值的情況,另一個處理沒返回值的情況。
第三個和第四個重載形式繼承于std::_Function_base::_Ref_manager,可以看出它們基本上算是前兩個類的偏特化版本,當(dāng)?shù)诙€模板參數(shù)為std::reference_wrapper包裝的引用時,就調(diào)用這兩個偏特化的版本。這兩個重載形式的唯一區(qū)別也是它們一個處理函數(shù)有返回值的情況,另一個處理沒返回值的情況?,F(xiàn)在問題來了,為什么要搞一個對于std::reference_wrapper類型的偏特化版本呢?這是因為如果可調(diào)用實體已經(jīng)先被std::reference_wrapper包裝過的話,那我們是絕對絕對不能直接調(diào)用這個可調(diào)用實體的,因為此時根本不確定這個被包裝的可調(diào)用實體究竟是什么類型的,如果是類成員函數(shù)的話那當(dāng)然是不能直接調(diào)用的,此時必須使用std::mem_fn來獲取一個可調(diào)用的對象,類中使用的std::__callable_functor函數(shù)的實現(xiàn)如下面的代碼所示,可以看到有好幾種特化版本,當(dāng)std::reference_wrapper包裝的可調(diào)用實體是一個類成員函數(shù)指針時,就會通過std::mem_fn來獲取一個可調(diào)用的對象,這和前面描述的內(nèi)容一致。
templateinline _Functor& __callable_functor(_Functor& __f) { return __f; } template inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* &__p) { return std::mem_fn(__p); } template inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* const &__p) { return std::mem_fn(__p); } template inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* volatile &__p) { return std::mem_fn(__p); } template inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* const volatile &__p) { return std::mem_fn(__p); }
關(guān)于上面提到的std::reference_wrapper和std::mem_fn,大家如果可以不懂的話一定要看下面兩篇文章,不然的話就像學(xué)英語不會英語單詞一樣,根本不可能看懂std::function的內(nèi)容的
《C++11的std::ref、std::cref源碼解析》
《C++11的std::mem_fn源碼解析》
第五個和第六個重載形式和前面的差不多,這兩個也是屬于偏特化版本,主要是用于處理可調(diào)用實體為類成員函數(shù)指針的情況,這里就可以看到直接調(diào)用了std::men_fn函數(shù)來使得我們可以直接調(diào)用對應(yīng)的類成員函數(shù),從這點也可以看出std::men_fn函數(shù)的重要性,不懂的小伙伴一定要去看前面兩篇文章啊。
每一個類里面的_M_invoke函數(shù)都用了_M_get_pointer(來源不全部相同),從代碼邏輯上不難看出_M_get_pointer函數(shù)的作用是從第一個傳入?yún)?shù)__functor中取出對應(yīng)的可調(diào)用實體,然后將后面的可變參傳給這個可調(diào)用實體,運行它,這個功能是不是就有點似曾相識了?對,這就是我們平時正常調(diào)用函數(shù)的那樣子嘛,也就是說std::function的函數(shù)執(zhí)行功能在這里實現(xiàn)了
從代碼中我們可以看出這幾個類都是和std::_Function_base相關(guān)的,并且到現(xiàn)在還是不知道_M_functor究竟是個什么東西,接下來分析std::_Function_base,看一下里面究竟做了哪些工作
_Any_data位于libstdc++-v3\include\std\functional中
union _Nocopy_types { void* _M_object; const void* _M_const_object; void (*_M_function_pointer)(); void (_Undefined_class::*_M_member_pointer)(); }; union _Any_data { void* _M_access() { return &_M_pod_data[0]; } const void* _M_access() const { return &_M_pod_data[0]; } template_Tp& _M_access() { return *static_cast<_Tp*>(_M_access()); } template const _Tp& _M_access() const { return *static_cast (_M_access()); } _Nocopy_types _M_unused; char _M_pod_data[sizeof(_Nocopy_types)]; };
看std::_Function_base之前先看一個重要的聯(lián)合體_Any_data,這個在前面出現(xiàn)很多次了,但是一直沒有介紹一下它究竟是個什么東西,下面簡單分析一下:
有兩個聯(lián)合體成員,一個是_M_unused(沒卵用),一個是_M_pod_data,這兩個的占用內(nèi)存是一樣的,具體原因就不講了,大家可以自己用sizeof去試一下
里面有四個_M_access函數(shù),前兩個是直接將_M_pod_data的地址返回出去,不做任何轉(zhuǎn)換,后兩個則是可以將_M_pod_data轉(zhuǎn)換為任意類型返回,從這里可以看出這個_Any_data的作用就是來接管可調(diào)用對象的,所以后續(xù)可以通過各種轉(zhuǎn)換將它還原為可調(diào)用的形式(比如前面提到的那個_Function_base::_Base_manager<_Functor>::_M_get_pointer方法就是干這個貨活的)
簡單看一下_Nocopy_types這個聯(lián)合體,前兩個成員的寓意就是類實例或Lambda表達式,第三個寓意是普通函數(shù)指針,第四個寓意是類成員函數(shù)指針,仔細(xì)一看這不就是我們前面提到無數(shù)次的可調(diào)用實體的幾種形式嗎?這個_Nocopy_types從上下文看來并沒有什么亂用,估計就是源碼作者寫給讀者看的吧,讓大家更容易讀懂源碼。
std::_Function_base的實現(xiàn)位于libstdc++-v3\include\std\functional中
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); templateclass _Base_manager { protected: 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 _Local_storage; 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); } static void _M_clone(_Any_data& __dest, const _Any_data& __source, true_type) { new (__dest._M_access()) _Functor(__source._M_access<_Functor>()); } static void _M_clone(_Any_data& __dest, const _Any_data& __source, false_type) { __dest._M_access<_Functor*>() = new _Functor(*__source._M_access<_Functor*>()); } 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*>(); } public: static bool _M_manager(_Any_data& __dest, const _Any_data& __source, _Manager_operation __op) { switch (__op) { 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; } static void _M_init_functor(_Any_data& __functor, _Functor&& __f) { _M_init_functor(__functor, std::move(__f), _Local_storage()); } template static bool _M_not_empty_function(const function<_Signature>& __f) { return static_cast (__f); } template static bool _M_not_empty_function(_Tp* const& __fp) { return __fp; } template static bool _M_not_empty_function(_Tp _Class::* const& __mp) { return __mp; } template static bool _M_not_empty_function(const _Tp&) { return true; } 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)); } }; template class _Ref_manager : public _Base_manager<_Functor*> { typedef _Function_base::_Base_manager<_Functor*> _Base; public: static bool _M_manager(_Any_data& __dest, const _Any_data& __source, _Manager_operation __op) { switch (__op) { case __get_functor_ptr: __dest._M_access<_Functor*>() = *_Base::_M_get_pointer(__source); return is_const<_Functor>::value; break; default: _Base::_M_manager(__dest, __source, __op); } return false; } static void _M_init_functor(_Any_data& __functor, reference_wrapper<_Functor> __f) { _Base::_M_init_functor(__functor, std::__addressof(__f.get())); } }; _Function_base() : _M_manager(0) { } ~_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和_M_manager,_M_functor就不用多說了,前面一直有提到它,他的類型_Any_data也在上一小節(jié)講過了。而_M_manager則是一個函數(shù)指針,下面再介紹它有什么用。
這里看一下_Function_base::_Base_manager類里面的各個方法
_M_init_functor函數(shù):該函數(shù)前面提到過了,當(dāng)時看到的是將std::function接管的可調(diào)用對象傳遞給了這個函數(shù),而從前面我們知道_Any_data類型的數(shù)據(jù)是可以接管所有形式的可調(diào)用實體的,所以綜合可得_M_init_functor函數(shù)的作用就是將傳遞給它的第二個參數(shù)儲存到第一個參數(shù)中(_Any_data類型數(shù)據(jù)),這樣就達成了接管可調(diào)用實體的功能了
_M_get_pointer函數(shù):這個函數(shù)同樣在前面提到過,當(dāng)時我們只知道通過調(diào)用_M_get_pointer可以獲取到我們接管的那個可調(diào)用實體,但是不知道是如何實現(xiàn)的,這里可以看出他的實現(xiàn)是非常簡單的,也就是從它的傳入?yún)?shù)(_Any_data類型數(shù)據(jù))將可調(diào)用實體取出,并強制轉(zhuǎn)換為合法的類型,里面用到了std::__addressof,作用就是即使目標(biāo)變量(類)存在operator&的重載,也依然能夠獲得變量的地址。
關(guān)于std::__addressof的詳細(xì)內(nèi)容可以看這篇文章《C++11的std::addressof源碼解析》
_M_manager函數(shù):該函數(shù)就是根據(jù)傳入的第三個參數(shù)來確定執(zhí)行不同的功能,其余的幾個函數(shù)無非就是涉及到內(nèi)存的分配和釋放之類的,對我們理解std::function的影響不大,這里就不展開講了
接下來看一下_Function_base::_Ref_manager類
可以看到該類繼承于_Function_base::_Base_manager類,可見他擁有_Function_base::_Base_manager類實現(xiàn)的所有功能
該類是處理當(dāng)std::function接管的是一個引用包裝類的情況的,為什么這種情況需要單獨處理呢?因為此時如果直接對傳入?yún)?shù)取地址,取到的將是引用包裝類的地址,而不是我們要接管的可調(diào)用對象的地址,所以只能搞這么一個特化版本,就像_Function_base::_Ref_manager類做的那樣,里面的_M_init_functor函數(shù)通過使用reference_wrapper的get方法獲取到了std::function接管的可調(diào)用對象的真實地址
_Function_base類里的其它方法就不講了,大家自己看一下吧,其余的實現(xiàn)基本都是基于前面講的那些內(nèi)容,比較簡單
關(guān)于“C++11中的std::function怎么用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。