0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C++ function技術(shù)的實現(xiàn)與具體運用

Linux愛好者 ? 來源:xdesk ? 作者:xdesk ? 2021-01-20 09:23 ? 次閱讀

【導(dǎo)讀】:本文主要講解C++ function技術(shù)的實現(xiàn)與具體運用。

std::function是一個函數(shù)對象的包裝器,std::function的實例可以存儲,復(fù)制和調(diào)用任何可調(diào)用的目標(biāo),包括:

函數(shù)。

lamada表達式。

綁定表達式或其他函數(shù)對象。

指向成員函數(shù)和指向數(shù)據(jù)成員的指針。

當(dāng)std::function對象沒有初始化任何實際的可調(diào)用元素,調(diào)用std::function對象將拋出std::bad_function_call異常。

本文我們來談一下std::function的實現(xiàn)原理。

1. std::function簡介

在討論其原理的時候,我們來熟悉一下這個東西是怎么使用的,C++標(biāo)準(zhǔn)庫詳細說明了這個的基本使用http://www.cplusplus.com/reference/functional/function/.

這里我們大概總結(jié)一下。

1.1 Member types

result_type 返回類型
argument_type 如果函數(shù)對象只有一個參數(shù),那么這個代表參數(shù)類型。
first_argument_type 如果函數(shù)對象有兩個個參數(shù),那么這個代表第一個參數(shù)類型。
second_argument_type 如果函數(shù)對象有兩個個參數(shù),那么這個代表第二個參數(shù)類型。
成員類型 說明

1.2 Member functions

constructor 構(gòu)造函數(shù):constructs a new std::function instance
destructor 析構(gòu)函數(shù):destroys a std::function instance
operator= 給定義的function對象賦值
operator bool 檢查定義的function對象是否包含一個有效的對象
operator() 調(diào)用一個對象
成員函數(shù)聲明 說明

1.3 基本使用

#include #include intfun(inta,intb,intc,intd) { std::cout<f; f=[](inta,intb,intc,intd)->int { std::cout<

從上面我們可以發(fā)現(xiàn),std::function可以表示函數(shù),lamada,可調(diào)用類對象。

2. std::function實現(xiàn)

在標(biāo)準(zhǔn)庫中STL設(shè)計為如下:

template struct_Arg_types {//provideargument_type,etc.(sometimes) }; template struct_Arg_types<_Ty1> {//provideargument_type,etc.(sometimes) typedef_Ty1argument_type; }; template struct_Arg_types<_Ty1,?_Ty2> {//provideargument_type,etc.(sometimes) typedef_Ty1first_argument_type; typedef_Ty2second_argument_type; }; template class_Func_class :public_Arg_types<_Types...> {//implementfunctiontemplate public: typedef_Retresult_type; typedef_Func_class<_Ret,?_Types...>_Myt; typedef_Func_base<_Ret,?_Types...>_Ptrt; private: bool_Local()const_NOEXCEPT {//testforlocallystoredcopyofobject return(_Getimpl()==_Getspace()); } union_Storage {//storageforsmallobjects(basic_stringissmall) max_align_t_Dummy1;//formaximumalignment char_Dummy2[_Space_size];//topermitaliasing _Ptrt*_Ptrs[_Num_ptrs];//_Ptrs[_Num_ptrs-1]isreserved }; _Storage_Mystorage; }; template struct_Get_function_impl<_Ret?CALL_OPT?(_Types...)> {/*determinetypefromargumentlist*/ typedef_Func_class<_Ret,?_Types...>type; }; template classfunction :public_Get_function_impl<_Fty>::type {//wrapperforcallableobjects public: typedeffunction<_Fty>_Myt; };

上面的std::function繼承關(guān)系比較簡單,主要使用

union_Storage { //storageforsmallobjects(basic_stringissmall) max_align_t_Dummy1;//formaximumalignment char_Dummy2[_Space_size];//topermitaliasing _Ptrt*_Ptrs[_Num_ptrs];//_Ptrs[_Num_ptrs-1]isreserved };

這個來存儲我們設(shè)置的可調(diào)用對象,我們從std::function的使用過程看一下整個原理。

2.1 函數(shù)對象賦值

我們使用的時候一般使用f = Caller;來設(shè)置函數(shù)對象,我們看下這個的實現(xiàn)過程。

template _Myt&operator=(reference_wrapper<_Fx>_Func)_NOEXCEPT { //assignwrapperholdingreference_wrappertofunctionobject this->_Tidy(); this->_Reset(_Func); return(*this); }

我們看this->_Reset(_Func)這個函數(shù),因為這個才是設(shè)置函數(shù)可調(diào)用對象的東西。

void_Set(_Ptrt*_Ptr)_NOEXCEPT {//storepointertoobject _Mystorage._Ptrs[_Num_ptrs-1]=_Ptr; } void_Reset_impl(_Fx&&_Val,const_Alloc&_Ax, _Myimpl*,_Alimpl&_Al,false_type) {//storecopyof_Valwithallocator,small(locallystored) _Myimpl*_Ptr=static_cast<_Myimpl?*>(_Getspace()); _Al.construct(_Ptr,_STDforward<_Fx>(_Val),_Ax); _Set(_Ptr); } template void_Reset_alloc(_Fx&&_Val,const_Alloc&_Ax) {//storecopyof_Valwithallocator if(!_Test_callable(_Val)) {//nullmemberpointer/functionpointer/std::function return;//alreadyempty } typedeftypenamedecay<_Fx>::type_Decayed; typedef_Func_impl<_Decayed,?_Alloc,?_Ret,?_Types...>_Myimpl; _Myimpl*_Ptr=0; typedef_Wrap_alloc<_Alloc>_Alimpl0; typedeftypename_Alimpl0::templaterebind<_Myimpl>::other_Alimpl; _Alimpl_Al(_Ax); _Reset_impl(_STDforward<_Fx>(_Val),_Ax, _Ptr,_Al,_Is_large<_Myimpl>()); } template void_Reset(_Fx&&_Val) { //storecopyof_Val _Reset_alloc(_STDforward<_Fx>(_Val),allocator()); }

這個代碼的主要意思就是創(chuàng)建一個_Func_impl<_Decayed, _Alloc, _Ret, _Types...>指針,然后賦值_Mystorage._Ptrs[_Num_ptrs - 1] = _Ptr;。

設(shè)置之后,我們看下調(diào)用操作怎么完成。

2.2 operator() 的實現(xiàn)

調(diào)用操作主要是通過operator()來實現(xiàn)的,我們看下這個的實現(xiàn)過程。

_Ptrt*_Getimpl()const_NOEXCEPT {//getpointertoobject return(_Mystorage._Ptrs[_Num_ptrs-1]); } _Retoperator()(_Types..._Args)const {//callthroughstoredobject if(_Empty()) _Xbad_function_call(); return(_Getimpl()->_Do_call(_STDforward<_Types>(_Args)...)); }

因此,我們是通過_Func_impl<_Decayed, _Alloc, _Ret, _Types...>轉(zhuǎn)發(fā)了調(diào)用操作_Do_call

2.3 _Func_impl的實現(xiàn)

class_Func_impl :public_Func_base<_Rx,?_Types...> {//derivedclassforspecificimplementationtypes public: typedef_Func_impl<_Callable,?_Alloc,?_Rx,?_Types...>_Myt; typedef_Func_base<_Rx,?_Types...>_Mybase; typedef_Wrap_alloc<_Alloc>_Myalty0; typedeftypename_Myalty0::templaterebind<_Myt>::other_Myalty; typedefis_nothrow_move_constructible<_Callable>_Nothrow_move; virtual_Rx_Do_call(_Types&&..._Args) {//callwrappedfunction return(_Invoke_ret(_Forced<_Rx>(),_Callee(), _STDforward<_Types>(_Args)...)); } _Compressed_pair<_Alloc,?_Callable>_Mypair; };

_Func_impl這個類通過_Do_call來轉(zhuǎn)發(fā)函數(shù)對象的調(diào)用操作。

3. 總結(jié)

這里我們看下std::function的結(jié)構(gòu)信息,如下:

330d8784-5788-11eb-8b86-12bb97331649.png

從這里我們發(fā)現(xiàn)_Storage大小為:

constint_Num_ptrs=6+16/sizeof(void*); constsize_t_Space_size=(_Num_ptrs-1)*sizeof(void*);

_Num_ptrs值為10。

如果我們賦值的對象有成員變量會是什么情況呢?例如如下:

classCCaller { public: intoperator()(inta,intb,intc,intd) { std::cout<f; f=Caller; f(10,20,30,40); return0; }

內(nèi)存結(jié)構(gòu)如下:

333686e8-5788-11eb-8b86-12bb97331649.png

由此我們可以發(fā)現(xiàn)std::function是利用一個_Compressed_pair<_Alloc, _Callable> _Mypair;拷貝了元素的數(shù)據(jù)信息。

主要的初始化過程為:

emplate void_Reset_alloc(_Fx&&_Val,const_Alloc&_Ax) {//storecopyof_Valwithallocator if(!_Test_callable(_Val)) {//nullmemberpointer/functionpointer/std::function return;//alreadyempty } typedeftypenamedecay<_Fx>::type_Decayed; typedef_Func_impl<_Decayed,?_Alloc,?_Ret,?_Types...>_Myimpl; _Myimpl*_Ptr=0; typedef_Wrap_alloc<_Alloc>_Alimpl0; typedeftypename_Alimpl0::templaterebind<_Myimpl>::other_Alimpl; _Alimpl_Al(_Ax); _Reset_impl(_STDforward<_Fx>(_Val),_Ax, _Ptr,_Al,_Is_large<_Myimpl>()); }

其中decay<_Fx>::type定義了_Compressed_pair<_Alloc, _Callable> _Mypair;中_Callable的類型,這個聲明如下(也就是去掉引用和其他屬性信息):

template structdecay {//determinesdecayedversionof_Ty typedeftypenameremove_reference<_Ty>::type_Ty1; typedeftypename_If::value, typenameremove_extent<_Ty1>::type*, typename_If::value, typenameadd_pointer<_Ty1>::type, typenameremove_cv<_Ty1>::type>::type>::typetype; };

至此,我們大致上完成了std::function的原理分析了,希望在后續(xù)的使用中,我們能夠知道std::function在什么情況下可以使用,以及背后完成的事情。

責(zé)任編輯:lq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4286

    瀏覽量

    62341
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2102

    瀏覽量

    73457
  • 初始化
    +關(guān)注

    關(guān)注

    0

    文章

    49

    瀏覽量

    11823

原文標(biāo)題:C++ std::function 技術(shù)淺談

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C語言和C++中結(jié)構(gòu)體的區(qū)別

    同樣是結(jié)構(gòu)體,看看在C語言和C++中有什么區(qū)別?
    的頭像 發(fā)表于 10-30 15:11 ?106次閱讀

    C7000優(yōu)化C/C++編譯器

    電子發(fā)燒友網(wǎng)站提供《C7000優(yōu)化C/C++編譯器.pdf》資料免費下載
    發(fā)表于 10-30 09:45 ?0次下載
    <b class='flag-5'>C</b>7000優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器

    ostream在c++中的用法

    ostream 是 C++ 標(biāo)準(zhǔn)庫中一個非常重要的類,它位于 頭文件中(實際上,更常見的是通過包含 頭文件來間接包含 ,因為 包含了 和 )。 ostream 類及其派生類(如 std::cout
    的頭像 發(fā)表于 09-20 15:11 ?434次閱讀

    C++語言基礎(chǔ)知識

    電子發(fā)燒友網(wǎng)站提供《C++語言基礎(chǔ)知識.pdf》資料免費下載
    發(fā)表于 07-19 10:58 ?7次下載

    C++實現(xiàn)類似instanceof的方法

    C++有多態(tài)與繼承,但是很多人開始學(xué)習(xí)C++,有時候會面臨一個常見問題,就是如何向下轉(zhuǎn)型,特別是不知道具體類型的時候,這個時候就希望C++ 可以向Java或者Python中有insta
    的頭像 發(fā)表于 07-18 10:16 ?520次閱讀
    <b class='flag-5'>C++</b>中<b class='flag-5'>實現(xiàn)</b>類似instanceof的方法

    C/C++中兩種宏實現(xiàn)方式

    #ifndef的方式受C/C++語言標(biāo)準(zhǔn)支持。它不僅可以保證同一個文件不會被包含多次,也能保證內(nèi)容完全相同的兩個文件(或者代碼片段)不會被不小心同時包含。
    的頭像 發(fā)表于 04-19 11:50 ?533次閱讀

    鴻蒙OS開發(fā)實例:【Native C++

    使用DevEco Studio創(chuàng)建一個Native C++應(yīng)用。應(yīng)用采用Native C++模板,實現(xiàn)使用NAPI調(diào)用C標(biāo)準(zhǔn)庫的功能。使用C
    的頭像 發(fā)表于 04-14 11:43 ?2455次閱讀
    鴻蒙OS開發(fā)實例:【Native <b class='flag-5'>C++</b>】

    使用 MISRA C++:2023? 避免基于范圍的 for 循環(huán)中的錯誤

    在前兩篇博客中,我們?向您介紹了新的 MISRA C++ 標(biāo)準(zhǔn)?和?C++ 的歷史?。在這篇博客中,我們將仔細研究以 C++ 中?for?循環(huán)為中心的特定規(guī)則。
    的頭像 發(fā)表于 03-28 13:53 ?716次閱讀
    使用 MISRA <b class='flag-5'>C++</b>:2023? 避免基于范圍的 for 循環(huán)中的錯誤

    c語言,c++,java,python區(qū)別

    C語言、C++、Java和Python是四種常見的編程語言,各有優(yōu)點和特點。 C語言: C語言是一種面向過程的編程語言。它具有底層的特性,能夠?qū)τ嬎銠C硬件進行直接操作。
    的頭像 發(fā)表于 02-05 14:11 ?2157次閱讀

    C++簡史:C++是如何開始的

    MISRA C++:2023,MISRA? C++ 標(biāo)準(zhǔn)的下一個版本,來了!為了幫助您做好準(zhǔn)備,我們介紹了 Perforce 首席技術(shù)支持工程師 Frank van den Beuken 博士撰寫
    的頭像 發(fā)表于 01-11 09:00 ?516次閱讀
    <b class='flag-5'>C++</b>簡史:<b class='flag-5'>C++</b>是如何開始的

    C語言和C++中那些不同的地方

    C語言雖說經(jīng)常和C++在一起被大家提起,但可千萬不要以為它們是一個東西?,F(xiàn)在我們常用的C語言是C89標(biāo)準(zhǔn),C++
    的頭像 發(fā)表于 12-07 14:29 ?894次閱讀
    <b class='flag-5'>C</b>語言和<b class='flag-5'>C++</b>中那些不同的地方

    開箱即用!教你如何正確使用華為云CodeArts IDE for C/C++!

    C/C++編碼體驗、方便的訪問華為云資源、簡單的引用華為云服務(wù)于一身,實現(xiàn)C/C++開發(fā)者在個人研發(fā)作業(yè)體驗和效率上的巨大提升。 為了幫助
    的頭像 發(fā)表于 11-29 17:40 ?743次閱讀
    開箱即用!教你如何正確使用華為云CodeArts IDE for <b class='flag-5'>C</b>/<b class='flag-5'>C++</b>!

    如何選擇創(chuàng)建c語言和c++

    選擇創(chuàng)建 C 語言和 C++ 都需要綜合考慮多個因素。在決定使用哪種語言之前,我們需要對這兩種語言的特點、優(yōu)缺點、適用場景、學(xué)習(xí)成本等進行全面的了解和對比。下面是關(guān)于選擇創(chuàng)建 C 語言和 C+
    的頭像 發(fā)表于 11-27 15:58 ?560次閱讀

    c++怎么開始編程

    C++是一種高級的、通用的編程語言,用于開發(fā)各種類型的應(yīng)用程序。它是從C語言演變而來,也是一種靜態(tài)類型語言,可以在不同的平臺上進行開發(fā)。C++具有高度的靈活性和性能,并且廣泛應(yīng)用于游戲開發(fā)、桌面
    的頭像 發(fā)表于 11-27 15:56 ?879次閱讀

    c++多行注釋快捷鍵

    C++中,多行注釋(也稱為塊注釋)是一種用于注釋大段代碼或多個語句的方法。當(dāng)你希望暫時禁用一些代碼或者解釋特定部分代碼的作用時,多行注釋是非常有用的。 在C++中,多行注釋以 /* 開始,以
    的頭像 發(fā)表于 11-22 10:24 ?7982次閱讀