But a lambda function isn't just a pointer. So what is it? Note, we're going to use Clang as an example. A lot of things in C++ are up to compiler dev's ...
blog
project
developerblog
Menu
BehindC++LambdaFunctions
source
20737wordsclangcppcpp
Lambdafunctionsarenotjustpointerstoafunction.Thisisobviouswhenyouthinkaboutit:ifthey'reanonymous,anddeclaredcompletelydifferently,somethingmustbedifferent.But,wecanassignapointertoafunctiontoalambdaeasily:
void(*ptr)()=[](){};
Sohowdoesthatwork?Weknowwe'rejustassigningtoapointer.Butalambdafunctionisn'tjustapointer.Sowhatisit?
Note,we'regoingtouseClangasanexample.AlotofthingsinC++areuptocompilerdev'simagination,alsoknownasimplementationspecific.SoifIsay"lambdashave12toes,"thatisbecauseClangdefineslambdasashaving12toes,notbecausetheyhavetohave12toes.
Lambdasareclasses
Whenyoudefinealambdafunction,you'rereallymakingaC++class.Thisclassimplementsthemethodoperator().Whenyoucallthelambda,you'rejustcallingthatoperatorimplementation.
Here'sasimpleC++programtoshowthat:
intmain(){
[](){}();
}
Thatlineinmainisjustdefiningalambdawithnocaptures([]),thattakesnoargument(()),withnobody({}),thencallingit(()).WecanactuallylookatwhatClangdevelopsastheASTwith:
clang++-Xclang-ast-dumplambda.cpp
We'llwalkthroughthelambdafunctionpiecebypiece.
LookingattheAST
TheASTisjusttheinternalrepresentationofthecodethatthecompilerlooksat.Let'slookatthemostobviouspartoftheLambdashenanigans(note,obviousisrelative):
`-CXXOperatorCallExpr0x17238c8<3>'void':'void'
|-ImplicitCastExpr0x1723858<9>'void(*)()const'
|`-DeclRefExpr0x17237d8<9>'void()const'lvalueCXXMethod0x1723190'operator()''void()const'
`-ImplicitCastExpr0x17238b0<3>'const(lambdaatlambda.cpp:2:3)'lvalue
`-MaterializeTemporaryExpr0x1723898<3>'(lambdaatlambda.cpp:2:3)'lvalue
`-LambdaExpr0x17236a0<3>'(lambdaatlambda.cpp:2:3)'
Alright.Whatwehavehereisacallexpression-that'sthelast()inourlambda.Then,wehavesomegibberishthatisClangdoinginternalconversionsinordertomakethetypesright.Finally,wehaveourtrustedLambdaExpr-ourlambda!Let'slookatwhat'sinthat.
`-LambdaExpr0x17236a0<3>'(lambdaatlambda.cpp:2:3)'
|-CXXRecordDecl0x1723050<3>col:3implicitclassdefinition
||-DefinitionDatalambdapass_in_registersemptystandard_layouttrivially_copyablecan_const_default_init
|||-DefaultConstructordefaulted_is_constexpr
|||-CopyConstructorsimpletrivialhas_const_paramneeds_implicitimplicit_has_const_param
|||-MoveConstructorexistssimpletrivialneeds_implicit
|||-CopyAssignmenttrivialhas_const_paramneeds_implicitimplicit_has_const_param
|||-MoveAssignment
||`-Destructorsimpleirrelevanttrivial
||-CXXMethodDecl0x1723190<6>col:3usedoperator()'void()const'inline
||`-CompoundStmt0x1723240<7>
||-CXXConversionDecl0x1723538<3>col:3implicitoperatorvoid(*)()'void(*()constnoexcept)()'inline
||-CXXMethodDecl0x17235e8<3>col:3implicit__invoke'void()'staticinline
|`-CXXDestructorDecl0x17236d0<3>col:3implicitreferenced~'void()noexcept'inlinedefaulttrivial
`-CompoundStmt0x1723240<7>
Oh,gosh.We'llgopiecebypiecethroughthis,buthere'sourclass.ACXXRecordDeclinClangrepresentsaC++struct,union,orclass.Soourlambdaactuallycontainsthatclassinitsnode.
WecanevenseethatinClangdocumentation.IfwegotothedocumentationforLambdaExprinClang,wecanactuallyseeabunchofusefulfunctions.Notably,wecanseegetLambdaClass(),whichwill"retrievetheclassthatcorrespondstothelambda."Neat!
We'llskiptheDefinitionDatapartoftheclass,sincethat'sjustdefiningsomedefaultconstructorsandwhatnot.Let'slookattheoperator()definition:
||-CXXMethodDecl0x1723190<6>col:3usedoperator()'void()const'inline
||`-CompoundStmt0x1723240<7>
Herewehaveourcalloperator.It'sempty,andreturnsvoid,soit'snotlikeweexpecttoseemuch.But,let'smakeithavesomething.Ifwechangeourlambdafunctionto:
[](){inti=1;}();
Wenowhavesomethinginourfunctionbody,soweexpecttoseeitinthecalloperator:
||-CXXMethodDecl0x171f190<6>col:3usedoperator()'void()const'inline
||`-CompoundStmt0x171f2f8<7>
||`-DeclStmt0x171f2e0<8>
||`-VarDecl0x171f258<8>col:12i'int'cinit
||`-IntegerLiteral0x171f2c0<16>'int'1
Andtherewehaveit,ourcalloperatorhasabody,justnestedintheAST.Howaboutareturntype?
[](){return1;}();
IntheAST:
||-CXXMethodDecl0x1f88190<6>col:3usedoperator()'int()const'inline
||`-CompoundStmt0x1f883b8<7>
||`-ReturnStmt0x1f883a8<8>
||`-IntegerLiteral0x1f88240<15>'int'1
Aswecansee,ourCXXMethodDeclchangedfromvoid()consttoint()const,showingourchangeinreturntype!
Finally,howaboutaddingaparameter?
[](inti){}(1);
AST:
||-CXXMethodDecl0xe84220<11>col:3usedoperator()'void(int)const'inline
|||-ParmVarDecl0xe83fc8<6>col:10i'int'
||`-CompoundStmt0xe842d8<12>
WecanseethattheCXXMethodDeclisnowvoid(int)constandwehaveaParmVarDecl(justafunctionparameter)insideofthemethoddecl.Awesome.
But,lambdasalsoletyoucaptureavariable.ThismeansthatifIhaveavariableioutsideofthelambda,captureit,changeit,thencallthelambda,weshouldseethatvariablechange.Let'stryitout:
#include
intmain(){
inti;
autolambda=[&i](){
std::cout<col:5implicit'int&'
Wehaveafieldinsideofourlambda'sclassnow!It'sareferencetoanint,namelytoideclaredoutside.Then,whenweuseourlambda,wejustusethatfield!Neat.
Now,wedon'ttakeaparameter,westillreturnvoid,canweassignthistoaCfunctionpointerlikewedidatthebeginning?
intmain(){
inti;
void(*ptr)()=[&i](){};
}
Thecompilererrors!
lambda.cpp:5:10:error:noviableconversionfrom'(lambdaatlambda.cpp:5:19)'to'void(*)()'
void(*ptr)()=[&i](){};
^~~~~~~~~
It'sweirdbecausewestillhaveallthequalificationsofthatfunctionpointer.But,ifwelookattheAST,we'llseesomethingmissingfromtheLambda'sclass,particularly:
||-CXXConversionDecl0x142f7b8<19>col:19implicitusedoperatorvoid(*)()'void(*()constnoexcept)()'inline
||`-CompoundStmt0x142fba0<19>
||`-ReturnStmt0x142fb90<19>
||`-ImplicitCastExpr0x142fb78<19>'void(*)()'
||`-DeclRefExpr0x142fb58<19>'void()'lvalueCXXMethod0x142f868'__invoke''void()'
Clangactuallyrefusestogenerateaconversiontothefunctionpointerifwehaveanycaptures!Thatmakessensebecausethefunctionnowreliesonthatvariablei.
Let'ssaywe'rereallycuriousandneedtoknowwhythishappened.Howcanwedothat?
DivingintoClang'scode
Luckily,Clang'ssourcecodeisopensource.Youcanfindit,alongwithLLVMandmore,onGithub.Furthermore,ifyouwanttoknowsomethinghighlevelaboutClang'scode,checkouttheClanginternalsmanual.
But,ourjobissimple:findoutwhereitrefusestogeneratetheconversionfunction.
Thefirstplacetostartrequiresabitofcompilerknowledge.ClanghasaSemalibraryforcertainsemanticactions.ThisSemalibraryiswhatbuildstheAST.Consideringthat,weprobablyhaveagoodplacetostart,sincewenoticedadifferenceintheAST.
Atthistime,youcanfindtheSemalibraryontheGithubunderllvm-project/clang/lib/Sema/
Nowthatwe'rehere,wewanttoseewhatcreatesthelambdafunction.Asolidwaytodothiswouldbetolookuptheconstructorinthedocumentationandseewhatcallsitandwhen.But,ourcaseislucky:there'safilecalledSemaLambda.cpp,solet'scheckthatout.
Ifwedigaroundhere,wefindthefunctionBuildLambdaExpr.Seemspromising.
Fromthere,let'sjustlookthroughthefunction.
Firstwedosomesetupfrompreviouslygatheredinfo:
CallOperator=LSI->CallOperator;
Class=LSI->Lambda;
IntroducerRange=LSI->IntroducerRange;
ExplicitParams=LSI->ExplicitParams;
ExplicitResultType=!LSI->HasImplicitReturnType;
LambdaCleanup=LSI->Cleanup;
ContainsUnexpandedParameterPack=LSI->ContainsUnexpandedParameterPack;
IsGenericLambda=Class->isGenericLambda();
Then,wedosomelogiccheckingifcapturesareusedandgettingtheminagoodformforourAST.
Next,wecanseewhywedon'tgetourconversionfunction:
if(Captures.empty()&&CaptureDefault==LCD_None)
addFunctionPointerConversions(*this,IntroducerRange,Class,
CallOperator);
So,weonlyaddthefunctionpointerconversionifwehavenocapturesandthecapturedefaultisnone!
Ifyoureallywanttodiveintotheweeds,theClangdevsalsooftencommentthepartofthestandardtheytookfrom:
//C++11[expr.prim.lambda]p6:
//Theclosuretypeforalambda-expressionwithnolambda-capture
//hasapublicnon-virtualnon-explicitconstconversionfunction
//topointertofunctionhavingthesameparameterandreturn
//typesastheclosuretype'sfunctioncalloperator.
Youcanfindthisyourselftoo!JustlookaroundforC++standards(likethroughopen-std.orgorjustasearchengine)andfindthesectionwithexpr.prim.lambda.You'llseenumbering,findnumber6,andyou'llfindidenticalorsimilarwordingtothat.
Wasthisaboutlambdas?
Notreally.LambdaswerejustamechanismforshowinghowtofindoutmoreaboutC++bydiggingintoit.Thisappliestoanylanguageorcompilertoo,especiallyiftheyletyoudumpast(orsomeintermediaterepresentation).It'salsojustfuntolookatcomplexcode.
Sothereyougo.Trythisoutthenexttimeyouseeaweirdconstructinyourfavoritelanguage.Sometimes,you'llgetsurprisedandfallintoafunrabbithole.It'swortheveryhour.
Project:cpp
Aboutthistopic(BehindC++LambdaFunctions),Wefoundmoreinformationhere,checkoutthelink
https://dev.to/evantypanski/behind-c-lambda-functions-2169
FOCUSONFINDINGGREATDEVELOPERCONTENT
(CollectionandSharebasedontheCCProtocol.)
LeetCode189.RotateArray(javascriptsolution)
TypingeffectinReactwithtyped.jsandhooks
RelatedPosts
Directiveslikeng-showdonotwork
Amnotyetsureifthisisbecauseofaproblemwithmy$parseimplementation,orwhetherwewillneedtoimplementclang-show,etc.
ActuallyIbelievetheystillworkwithregulardataonthescope,justnotwithclojur...
Ininterpolationsonlyjs-stylefunctionswork
Theclojurestyleoneshouldworkbutappearnottolookupthefunctioncorrectly.
oopsIalreadycreatedthisone...
Textinputlosesfocusoneverykeystroke
Thisappearstohappenbecausethechangeisbeingappliedtothecollectionwhichcausesittore-render.
Theupshotisthatyouneedtohavemutabilityavailabletoyouforpropertiesthatneedtostayfocussedwhilet...
clangseemsnotsuchagoodprojectname
clangisalreadybeingusedforcompilingc/c++,soyourprojectmightfinditdifficulttobefoundhttp://clang.llvm.org/
Hey,yeahI'mawareoftheotherproject,butIdon'tthinkthere'sanychanceofconfusion.
If...
can'trequire`clang.js-types`
WhenIrequireclang.js-typesinoneofmy.cljsfile,leincljsbuildautogivesthefollowingwarnings:
WARNING:UseofundeclaredVarclang.js-types/INamedatline28/Users/xhh/builds/clang/client/clang/js_types.cljs...
Brokenonlein-cljsbuild0.3.2
Buildingaprojectwithclang-0.1.0-SNAPSHOT,lein-cljsbuild0.3.2andclojurescript-0.0-1803causesthefollowingerror:
Notsureaboutthesourceoftheproblem,willseeifwecangetthisfixedup.
Inthemeantime,p...
scope!appearsinthereadmebutnotinthecode
Idecidedtoremovescope!
in7a9ce9d0229dcb33451b0d663368c6394943dc1cwhenIextendedthebuilt-inJSdatatypeswithgoodsupportforclojure'sstandardprotocols.
Ithinkthisisbettersincethescope!
Settingavalu...
IsClangstable?
Hello,
Ihavetwoquestions:-Clangisitreadytodevelopproductiontools?
-WhenwillclangpushonClojar?
No,youshouldn'tconsideritproductionreadyunlessyouarewillingtodiveinandfixorextendclang...
"clang.todo"and["clang"]meaning
Isitpossibletoexplainwhatarethesemanticsof"clang.todo"and["clang"]inthecontextofyourprojectsample?
OKIgotthemeaningbyopeninghttps://github.com/pangloss/clang/blob/master/resources/public/index.h...
HigherlevelthreadinginC++
Herethestd::condition_variablecomestotherescue,thisissynchronizationprimitivethatcanbeusedtoblockthreads,untilanotherthreadmodifiesthewaitconditionandnotifiesthewaitingthread.
notify:Thisfu...
🍪Thiswebsiteusescookiestoensureyougetthebestexperienceonourwebsite.
Learnmore
IGotIt
19>19>19>19>19>12>6>11>15>8>7>6>16>8>8>7>6>7>6>7>3>3>3>7>6>3>3>3>3>3>9>9>3>