It is possible to pass lambda functions as arguments where function pointers are expected. Of course the signature of the lamda function should match the ...
FunctionPointers
Considerthefollowingfile
square.cpp
#include
usingstd::cout;
usingstd::endl;
intsquare(intx)
{
returnx*x;
}
intmain()
{
int(*fnptr)(int);
fnptr=square;
cout<g++square.cpp-osquare
>./square
4
Herestatementint(*fnptr)(int)declaresavariablefnptrthatcanstoreapointertoafunctionthattakesoneintargumentandreturnsanint.Intheaboveprogramsquareissuchafunction.Functionsquaretakesoneintargumentandreturnsanint.Wecanassigntheaddressofthisfunctiontovariablefnptrusingtheassignmentfnptr=square.Notethatthenameofthefunctionisalsoitsaddress.So,wedon’tneedtousethe&togettheaddressofthisfunction.Wecanthencallthefunctionsquarebyusingthevariablefnptr.
Example1
Considerthefollowingfunction
voidswap(float*a,float*b)
{
floattmp;
tmp=*a;
*a=*b;
*b=tmp;
}
Wecandeclareavariabletostorethepointertofunctionswapasfollows
void(*m)(float*a,float*b);
Wecanthenassigntheaddressoffunctionswaptovariablemasfollows
m=swap;
Example2
Considerthefollowingfunction
boolgt(inta,intb)
{
returna>b;
}
Wecandeclareavariabletostorethepointertofunctiongtasfollows
bool(*l)(inta,intb);
Wecanthenassigntheaddressoffunctiongttovariablelasfollows
l=gt;
Example3
Considerthefollowingfunction
doublesum(doublea[],inti,intj,ints)
{
doublesum=0.0;
for(intk=i;k<=j;k+=s){
sum+=a[k];
}
returnsum;
}
Wecandeclareavariabletostorethepointertofunctionsumasfollows
double(*n)(doublea[],inti,intj,ints)
Wecanthenassigntheaddressoffunctionsumtovariablenasfollows
n=sum;
Functionpointersasarguments
Havingvariablesthatcanstorepointerstofunctionsallowustopassfunctionsasargumentstootherfunctions.Theseisaverypowerfulfeaturethatenablesustowritecodewhereprocessingcanchangeonthefly.
Considerthefollowingcode.Heredo_some_processisafunctionthatreliesuponthefunctionpassedtoitasitsargumenttodotheactuallyprocessing.Thismeansthatwecanchangethebehaviorofdo_some_processbypassingadifferentfunctionatruntime.
function-ptr-arguments.cpp
#include
usingstd::cout;
usingstd::endl;
intsquare(intx)
{
returnx*x;
}
intneg(intx)
{
return-x;
}
intdo_some_process(int(*fn)(int),intx)
{
returnfn(x);
}
intmain()
{
intx=5;
cout<g++function-ptr-arguments.cpp-oprog
>./prog
25
-5
Listenerandcallbackfunctions
Functionpointersarefrequentlyusedtosetuplistenerorcallbackfunctions.Thesefunctionareinvokedwhenacertaineventoccurs.Theseprovideaneasywayforausertoinjecttheirownfunctionalityintoalargersystem.Toreiteratethispointe,functionpointersareoftenusedtopassaroundprocessinginstructions.
BelowyouseeanexampleofacallbackfunctionfortheGLUTlibrarythatallowsausertorespondtomouseevents.
voidglutMouseFunc(void(*func)(intbutton,intstate,intx,inty));
Virtualfunctions
Itisalsopossibletoavoidexplicitfunctionpointersbyusingvirtualfunctionsandpolymorphism.Virtualfunction,however,areimplementedbehindthesceneusingfunctionpointers.
C++Functors
Inadditiontofunctionpointersseenabove,C++alsoprovidesfunctors.Functorsareobjectsthatcanbeusedasifthesearefunctions.Functorsaremorepowerfulthangood’olfunctionpointers,sincefunctorscancarryaroundstate.
Considerthecodebelow:
functors.cpp
#include
usingstd::cout;
usingstd::endl;
classSquare{
public:
intoperator()(intx){
returnx*x;
}
};
intmain()
{
Squarea;
cout<
usingstd::cout;
usingstd::endl;
classSquare{
public:
intoperator()(intx){
returnx*x;
}
};
classNeg{
public:
intoperator()(intx){
return-x;
}
};
template
intdo_some_process(Tprocess,intx)
{
returnprocess(x);
}
intmain()
{
Squarea;
Negb;
cout<intdo_some_process(Tprocess,intx){...}isthatitalsoallowsustopassinfunctionsasbelow
#include
usingstd::cout;
usingstd::endl;
classSquare{
public:
intoperator()(intx){
returnx*x;
}
};
classNeg{
public:
intoperator()(intx){
return-x;
}
};
inttimestwo(intx)
{
return2*x;
}
template
intdo_some_process(Tprocess,intx)
{
returnprocess(x);
}
intmain()
{
Squarea;
Negb;
intx=9;
cout<
usingstd::cout;
usingstd::endl;
intmain()
{
autofunc=[](intx)->int{returnx*x;};
intx=11;
cout<int{returnx*x;}definesthelambdafunction.Here[]iscompilerspecification,indicatingthecompilerthatwearecreatingalambdafunction.()isusedtospecifytheargumentlist.Inthiscase,thisfunctiontakesoneargumentoftypeint,henceweuse(intx).->intindicatesthereturntype.Inthiscasethefunctionreturnsanint.{returnx*x;}isthefunctionbody.Herethelambdafunctioniscreatedanditspointerisassignedtovariablefunc.autoisakeywordthatcanbeusedtodefineavariable.Inthiscasethetypeofthevariableisinferedfromcontext.
Syntacticsugar
Itisokaytomiss()ifthefunctiontakesnoarguments.
Itisokaytomiss->ifthecompilercandiscerntheretunrtype.
Itispossibletocallthefunctionrightawaybyusing()attheendofthebodyasshownbelow
Seetheexamplebelow.
#include
usingstd::cout;
usingstd::endl;
intmain()
{
intval=11;
cout<
usingstd::cout;
usingstd::endl;
intdo_some_process(intx,int(*process)(int))
{
returnprocess(x);
}
intmain()
{
cout<int{returnx*x;})<
usingstd::cout;
usingstd::endl;
intmain()
{
intval=11;
cout<
usingstd::cout;
usingstd::endl;
classDisk
{
protected:
double_radius;
constdouble_pi;
public:
Disk()
:_radius(10),_pi(3.14159)
{}
doublearea(){
return
//Notethatthefollowingisalambdafunction.
//
//Thereturntypeisn'tspecificed,sinceitcanbedeterminedbythe
//compilerfromcontext.(itisadouble)
//
//Thefunctiondoesn'ttakeanyargumentseither.Notetheempty
//()thattellusthatitisafunctioncall.
//
//Through[this]thelambdafunctioncapturesthethispointer
//forthecurrentinstanceofDiskclass.Usingthisitisthen
//abletoaccesstheprivatemembers(data)andmethods(functions).
[this]{returnthis->_pi*this->_radius*this->_radius;}();
};
};
intmain()
{
intx=1,y=2,z=3;
cout<int{returna+b;}(x,y)<int{x=5;returnx+y;}()<int{
/*thisstatementgivesacompileerrorx=10;*/
returnx+y;}()<int{
/*thisstatementgivesacompileerror,becauseyisn'tavailable
withinthelambdafunctionreturnx+y;*/
returnx;}()<int{
/*thisstatementgivesacompileerror,becausezisn'tavailable
withinthelambdafunctionreturnx+y+z;*/
y=10;
returnx+y;}()<
#include
usingstd::cout;
usingstd::endl;
intmain()
{
std::vectorv;
for(inti=0;i<10;++i)v.push_back(i*2);
std::for_each(v.begin(),v.end(),[](intval){cout<