在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C++ function技術的實現與具體運用

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

【導讀】:本文主要講解C++ function技術的實現與具體運用。

std::function是一個函數對象的包裝器,std::function的實例可以存儲,復制和調用任何可調用的目標,包括:

函數。

lamada表達式。

綁定表達式或其他函數對象。

指向成員函數和指向數據成員的指針。

當std::function對象沒有初始化任何實際的可調用元素,調用std::function對象將拋出std::bad_function_call異常。

本文我們來談一下std::function的實現原理。

1. std::function簡介

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

這里我們大概總結一下。

1.1 Member types

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

1.2 Member functions

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

1.3 基本使用

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

從上面我們可以發現,std::function可以表示函數,lamada,可調用類對象。

2. std::function實現

在標準庫中STL設計為如下:

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繼承關系比較簡單,主要使用

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

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

2.1 函數對象賦值

我們使用的時候一般使用f = Caller;來設置函數對象,我們看下這個的實現過程。

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

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

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()); }

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

設置之后,我們看下調用操作怎么完成。

2.2 operator() 的實現

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

_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...>轉發了調用操作_Do_call

2.3 _Func_impl的實現

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來轉發函數對象的調用操作。

3. 總結

這里我們看下std::function的結構信息,如下:

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

從這里我們發現_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; }

內存結構如下:

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

由此我們可以發現std::function是利用一個_Compressed_pair<_Alloc, _Callable> _Mypair;拷貝了元素的數據信息。

主要的初始化過程為:

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的原理分析了,希望在后續的使用中,我們能夠知道std::function在什么情況下可以使用,以及背后完成的事情。

責任編輯:lq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4346

    瀏覽量

    63012
  • C++
    C++
    +關注

    關注

    22

    文章

    2114

    瀏覽量

    73885
  • 初始化
    +關注

    關注

    0

    文章

    50

    瀏覽量

    11954

原文標題:C++ std::function 技術淺談

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

收藏 人收藏

    評論

    相關推薦

    Spire.XLS for C++組件說明

    Spire.XLS for C++ 是一款專業的 C++ Excel 組件,可以用在各種 C++ 框架和應用程序中。Spire.XLS for C++ 提供了一個對象模型 Excel
    的頭像 發表于 01-14 09:40 ?164次閱讀
    Spire.XLS for <b class='flag-5'>C++</b>組件說明

    EE-112:模擬C++中的類實現

    電子發燒友網站提供《EE-112:模擬C++中的類實現.pdf》資料免費下載
    發表于 01-03 15:15 ?0次下載
    EE-112:模擬<b class='flag-5'>C++</b>中的類<b class='flag-5'>實現</b>

    AKI跨語言調用庫神助攻C/C++代碼遷移至HarmonyOS NEXT

    )開發框架。它極大地簡化了JS與C/C++之間的跨語言訪問,為開發者提供了一種邊界性編程體驗友好的解決方案。通過AKI,開發者可以使用讓代碼更易讀的語法糖,實現JS與C/
    發表于 01-02 17:08

    運動控制卡周期上報實時數據IO狀態之C++

    使用C++進行運動控制卡的周期上報功能實現
    的頭像 發表于 12-17 13:59 ?354次閱讀
    運動控制卡周期上報實時數據IO狀態之<b class='flag-5'>C++</b>篇

    C7000 C/C++優化指南用戶手冊

    電子發燒友網站提供《C7000 C/C++優化指南用戶手冊.pdf》資料免費下載
    發表于 11-09 15:00 ?0次下載
    <b class='flag-5'>C</b>7000 <b class='flag-5'>C</b>/<b class='flag-5'>C++</b>優化指南用戶手冊

    C語言和C++中結構體的區別

    同樣是結構體,看看在C語言和C++中有什么區別?
    的頭像 發表于 10-30 15:11 ?362次閱讀

    C7000優化C/C++編譯器

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

    ostream在c++中的用法

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

    OpenVINO2024 C++推理使用技巧

    很多人都使用OpenVINO新版的C++ 或者Python的SDK,都覺得非常好用,OpenVINO2022之后的版本C++ SDK做了大量的優化與整理,已經是非常貼近開發的使用習慣與推理方式。與OpenCV的Mat對象對接方式更是幾乎無縫對接,非常的方便好用。
    的頭像 發表于 07-26 09:20 ?1064次閱讀

    C++語言基礎知識

    電子發燒友網站提供《C++語言基礎知識.pdf》資料免費下載
    發表于 07-19 10:58 ?8次下載

    C++實現類似instanceof的方法

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

    C/C++中兩種宏實現方式

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

    鴻蒙OS開發實例:【Native C++

    使用DevEco Studio創建一個Native C++應用。應用采用Native C++模板,實現使用NAPI調用C標準庫的功能。使用C
    的頭像 發表于 04-14 11:43 ?2788次閱讀
    鴻蒙OS開發實例:【Native <b class='flag-5'>C++</b>】

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

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

    verilog task和function區別

    verilog中的task和function都是用于實現模塊中的可重復的功能,并且可以接收參數和返回結果。但是它們在編寫和使用上有一些區別。下面將詳細介紹task和function的區別。 語法結構
    的頭像 發表于 02-22 15:53 ?1200次閱讀
    主站蜘蛛池模板: 亚洲欧洲色 | 一级毛片免费网站 | 韩国三级日本三级在线观看 | 天天躁日日躁狠狠躁中文字幕老牛 | 二级黄色大片 | 一区二区三区高清在线观看 | 久久亚洲精品成人综合 | 亚洲成年人免费网站 | 色偷偷网 | 好吊色青青青国产在线观看 | www黄色大片| 国产黄色在线看 | 三级在线观看 | 午夜精品久久久久久久第一页 | 久久精品国产免费观看99 | 四虎影院成人在线观看 | 九色综合伊人久久富二代 | 女人张开腿让男人桶免费网站 | 黄色视屏日本 | 日韩欧美一区二区三区不卡视频 | 成人亚洲欧美在线电影www色 | 午夜tv| 91福利社在线观看 | 国产又色又爽又黄的网站在线一级 | 国产在线一区二区三区四区 | 国产单男 | 日本一区二区三区四区视频 | 一道精品视频一区二区三区男同 | 天堂网免费| cijilu刺激 国产免费的 | 爱婷婷视频在线观看 | 国产91色综合久久免费分享 | 午夜在线观看免费视频 | 天天做天天爱天天爽天天综合 | 天堂bt| 天天综合亚洲 | 超级乱淫视频播放日韩 | 欧美性色视频 | 天天成人综合网 | 久久婷婷丁香七月色综合 | 黄色一级视频欧美 |