c++裡的bind和lambda,為什麼沒辦法變成c-style function ...

文章推薦指數: 80 %
投票人數:10人

在c裡面,function pointer是一個儲存function位置的指標,可以拿來pass一個function讓別人呼叫,通常用來實作callback function。

c++裡的bind和lambda,為什麼沒辦法變成c-stylefunctionpointer2019/12/17C/C++共2501字,約8分鐘在c裡面,functionpointer是一個儲存function位置的指標,可以拿來pass一個function讓別人呼叫,通常用來實作callbackfunction。

例如natsclib裡的errorhandling,為了識別或做一些hacky技巧,還會指定一個void*讓它傳回來。

關於void*,最直觀的例子就是pthread_create裏頭的parameter了,例如這個的example然而有些設計不良的API是沒有提供這個實用的方式的,於是我開始尋找使用C++的方式把這個東西丟進去,例如bindtypedefvoid(*handler)(); voidrun(handlerh) { h(); } voidgg(inti){} intmain(){ run(bind(gg,3)); return0; } 然後編譯器就生氣了error:cannotconvert‘std::_Bind_helper::type{akastd::_Bind}’to‘handler{akavoid(*)()}’forargument‘1’to‘voidrun(handler)’ 一段一開始看不太懂的錯誤,上StackOverflow找找看,發現有人提供轉成std::function的方法,馬上抄來試試看。

intmain(){ functionf=(bind(gg,3)); handler*h=f.target(); if(!h)return1; run(*h); return0; } 編譯過了,但是果然return1。

沒辦法了,試試看lambda吧。

intmain(){ inti=3; functionf=([i](){}); handler*h=f.target(); if(!h)return1; run(*h); return0; } 果不其然也return1了。

到底是為什麼呢,只好來仔細的研究看看。

先從bind開始吧,c++有個半殘但勉強能用的東西可以揭開他們的真面目..typeid(x)inti=3; autolambda=[i](){}; autob=bind(gg,i); functionf=([i](){}); cout< std::function 先來看bind,根據sourcecodetemplate struct_Bind; 原來根本不是什麼function,是struct阿,那它是怎麼呼叫的呢,繼續往下找//Callunqualified template>> _Result operator()(_Args&&...__args) { returnthis->__call<_result>( std::forward_as_tuple(std::forward<_args>(__args)...), _Bound_indexes()); } 原來是overloadoperator(),再繼續往下看__call怎麼實作的//Callunqualified template _Result __call(tuple<_args...>&&__args,_Index_tuple<_indexes...>) { returnstd::__invoke(_M_f, _Mu<_bound_args>()(std::get<_indexes>(_M_bound_args),__args)... ); } 內部用了invoke執行該function,而參數_M_f和_M_bound_args其實是struct的member_Functor_M_f; tuple<_bound_args...>_M_bound_args; 而std::function其實就是個可以封裝各種functor物件或functionpointer的class把bind傳給std::function只是把它藏進去,還是沒辦法變成functionpointer。

也就是說std::function應該視為function的interface用來進行傳遞和呼叫。

而lambda就沒有實際出現在c++header裡了,不過在cppreference裡就有基本的說明Constructsaclosure:anunnamedfunctionobjectcapableofcapturingvariablesinscope. lambda也是個functionobject,但與bind最大的差別在bind要提供一個具名的function,但lambda儲存的是匿名function,並且是由編譯器幫忙完成的,相對的bind是藉由template展開來完成。

文件訊息作者:JiaJunYeh連結:https://xnum.github.io/2019/12/cpp-function/本著作係採用創用CC姓名標示-非商業性-相同方式分享3.0台灣授權條款授權.SearchTableofContents



請為這篇文章評分?